www.digitalmars.com         C & C++   DMDScript  

D - Programmable block statements.

reply "anderson" <anderson badmama.com.au> writes:
Yet again, another idea.

I think it would be cool if you could program your own block statements.
Often you need to have open/close statements (like with files). If you can
force the user to call them in a certain order using programmable block
statements, I think it would save a lot of bugs.

Of course the idea I present here is only a prototype.

Class ABC
{
    void open(char * FileName, block Enter)
    {
        if (Enter)
        {
            ...
        }
        else
        {
            ...
        }
    }
}

...

ABC x;

x.open("filename")
{

} //Closes here

You could also handle return types (if it had one). V would only be returned
after open (enter) had completed.

v = x.open("filename")
{

} //Closes here

And you could also use the function as-per-normal where block = boolean.

x.open("filename", true)
x.open("filename", false)

PS - I would suppose there were lots of ways of syntax'ing this, I tried to
choose an easily phaseable one.
Jan 20 2003
next sibling parent reply "Mike Wynn" <mike.wynn l8night.co.uk> writes:
use an auto class

File f;
if ( f = open() )
{
    auto FileCloser = new FileCloser( f );

   // closes here;
}

// I've not checked but you should be able to do;
auto class File {  }

whatever func( char[] name )
{
    char [] fullname = getFulName( name, cwd() );
    {  // braces SHOULD create a new scope (as in C)
        auto MyFile = new MyFile( fullname );
        ... stuff ...
        // will close here
    }
}


"anderson" <anderson badmama.com.au> wrote in message
news:b0ica3$21sj$1 digitaldaemon.com...
 Yet again, another idea.

 I think it would be cool if you could program your own block statements.
 Often you need to have open/close statements (like with files). If you can
 force the user to call them in a certain order using programmable block
 statements, I think it would save a lot of bugs.

 Of course the idea I present here is only a prototype.

 Class ABC
 {
     void open(char * FileName, block Enter)
     {
         if (Enter)
         {
             ...
         }
         else
         {
             ...
         }
     }
 }

 ...

 ABC x;

 x.open("filename")
 {

 } //Closes here

 You could also handle return types (if it had one). V would only be
returned
 after open (enter) had completed.

 v = x.open("filename")
 {

 } //Closes here

 And you could also use the function as-per-normal where block = boolean.

 x.open("filename", true)
 x.open("filename", false)

 PS - I would suppose there were lots of ways of syntax'ing this, I tried
to
 choose an easily phaseable one.
Jan 20 2003
parent reply "Mike Wynn" <mike.wynn l8night.co.uk> writes:
an example ....

pity you can't `with` an auto

then main could be

int main( char[][] args )
{
 MyFile res;
 printf("Starting ...\n");
 with( new Closer( new closer.MyBlock( &closeIt, 3, res ) ) ) {
  printf("[doing stuff]\n");
 }
 printf("end.\n");

 return 0;
}

almost exactly what you are after.

----------------------------
import c.stdio;

interface Closes
{
 bit close();
}

// work around because you can't have a destructor in a templated class
auto class Closer
{
 Closes toClose;
 this( Closes toClose0 ) { toClose = toClose0; }
 ~this() { toClose.close(); }
}

template delegatehelper( P, RV, T : RV (*)( P ) )
{
  class FcHelper
  {
   T toCall;
   this( T funcPtr ) { toCall = funcPtr; }
   RV evoke( P param ) { return toCall( param ); }
  }
}

template autocloser( T, P )
{
// auto class MyBlock
 class MyBlock : Closes
 {
  alias bit delegate ( T ) closeDelegate;
  alias bit (*closeFuncPtr)( T );

  closeDelegate onClose;
  T item;
/*  this( closeDelegate close0, P param, out T made )
  {
   init( close0, param, made );
  }*/

  this( closeFuncPtr close0, P param, out T made )
  {
   instance delegatehelper( T, bit, closeFuncPtr ) dh;
   dh.FcHelper conv = new dh.FcHelper( close0 );
   init( &conv.evoke, param, made );
  }

  void init( closeDelegate close0, P param, out T made )
  {
   made = item = new T( param );
   onClose = close0;
  }

/*  ~this()
  {
//   onClose( item );
  }*/

  bit close()
  {
   return onClose( item );
  }
 }
}

class MyFile { int i; this( int ii ) { i = ii; printf( "OPEN(%d)\n",
i ); } }


bit closeIt( MyFile f )
{
 printf( "CLOSE\n" );
 return true;
}

instance autocloser( MyFile, int ) closer;

int main( char[][] args )
{
 MyFile res;
 printf("Starting ...\n");
 {
  auto Closer autoClose = new Closer( new closer.MyBlock( &closeIt, 3,
res ) );
  printf("[doing stuff]\n");
 }
 printf("end.\n");

 return 0;
}
Jan 20 2003
parent reply "anderson" <anderson badmama.com.au> writes:
Close, but not quite. With that technique you need to create an object each
time you want this ability. But I get your point about it almost being in
the language.

Another point with that example is that it's weakly defined (in reguards to
using bracks or not) , because the users won't be force into using the brake
scope, which is an the idea I put forth.

"Mike Wynn" <mike.wynn l8night.co.uk> wrote in message
news:b0ih2k$24c9$1 digitaldaemon.com...
 an example ....

 pity you can't `with` an auto

 then main could be

 int main( char[][] args )
 {
  MyFile res;
  printf("Starting ...\n");
  with( new Closer( new closer.MyBlock( &closeIt, 3, res ) ) ) {
   printf("[doing stuff]\n");
  }
  printf("end.\n");

  return 0;
 }

 almost exactly what you are after.

 ----------------------------
 import c.stdio;

 interface Closes
 {
  bit close();
 }

 // work around because you can't have a destructor in a templated class
 auto class Closer
 {
  Closes toClose;
  this( Closes toClose0 ) { toClose = toClose0; }
  ~this() { toClose.close(); }
 }

 template delegatehelper( P, RV, T : RV (*)( P ) )
 {
   class FcHelper
   {
    T toCall;
    this( T funcPtr ) { toCall = funcPtr; }
    RV evoke( P param ) { return toCall( param ); }
   }
 }

 template autocloser( T, P )
 {
 // auto class MyBlock
  class MyBlock : Closes
  {
   alias bit delegate ( T ) closeDelegate;
   alias bit (*closeFuncPtr)( T );

   closeDelegate onClose;
   T item;
 /*  this( closeDelegate close0, P param, out T made )
   {
    init( close0, param, made );
   }*/

   this( closeFuncPtr close0, P param, out T made )
   {
    instance delegatehelper( T, bit, closeFuncPtr ) dh;
    dh.FcHelper conv = new dh.FcHelper( close0 );
    init( &conv.evoke, param, made );
   }

   void init( closeDelegate close0, P param, out T made )
   {
    made = item = new T( param );
    onClose = close0;
   }

 /*  ~this()
   {
 //   onClose( item );
   }*/

   bit close()
   {
    return onClose( item );
   }
  }
 }

 class MyFile { int i; this( int ii ) { i = ii; printf( "OPEN(%d)\n",
 i ); } }


 bit closeIt( MyFile f )
 {
  printf( "CLOSE\n" );
  return true;
 }

 instance autocloser( MyFile, int ) closer;

 int main( char[][] args )
 {
  MyFile res;
  printf("Starting ...\n");
  {
   auto Closer autoClose = new Closer( new closer.MyBlock( &closeIt, 3,
 res ) );
   printf("[doing stuff]\n");
  }
  printf("end.\n");

  return 0;
 }
Jan 20 2003
parent "Mike Wynn" <mike.wynn l8night.co.uk> writes:
if you could use an auto class with `with`
it's almost there, in your example you use one method with a bool param to
say open or close
the with way
with( new MyAutoObject( params ) ) {  // constructor called
 ... do stuff ...
} /// ~this (destructor called)

does everything you want, no syntax changes, no special cases.

as for creating an object every time, well D is a OO lang.

I don't know if they are, but auto objects could be stack allocated so there
is no overhead createing the space
(just sub sp, (sizeof(locals)+sizeof(autos)) in the function prolog.)
if your class only have methods and no members or few members its no great
overhead.

its basically the same technique C++ programmers have used for years, with
Lock and smart pointer classes
only C++ template syntax is a bit less verbose;


"anderson" <anderson badmama.com.au> wrote in message
news:b0ikm4$262l$1 digitaldaemon.com...
 Close, but not quite. With that technique you need to create an object
each
 time you want this ability. But I get your point about it almost being in
 the language.

 Another point with that example is that it's weakly defined (in reguards
to
 using bracks or not) , because the users won't be force into using the
brake
 scope, which is an the idea I put forth.
Jan 20 2003
prev sibling next sibling parent "Scott Pigman" <scottpig some.where.com> writes:
On Tue, 21 Jan 2003 10:50:41 +0800, anderson wrote:

 Yet again, another idea.
 
 I think it would be cool if you could program your own block statements.
 Often you need to have open/close statements (like with files). If you can
 force the user to call them in a certain order using programmable block
 statements, I think it would save a lot of bugs.
 
i second this.
Jan 20 2003
prev sibling next sibling parent reply Paul Stanton <Paul_member pathlink.com> writes:
a nice idea: improves readability by ensuring variables fall out of scope when
no longer needed therefore allowing the reader to disregard such properties
(which can also be achieved by writing a method somewhere else, but if your sure
you arnt gonna use it again, whats the point?).

basically, by doing this, you are saying "everything between "{" and "}" is only
required for [insert purpose here].

But this is not such a new idea, and can be easily achieved syntaxically in
current languages. You can use "{" and "}" anywhere you like, they are "scope"
parenthesis, therefore, anything defined inside, will fall out of scope when
exited.

You can already program yr own block statements
Jan 20 2003
parent Paul Stanton <Paul_member pathlink.com> writes:
ok, i missed the point
Jan 20 2003
prev sibling next sibling parent Patrick Down <pat codemoon.com> writes:
Ruby has a syntax that is similar to this. In Ruby
you could use the following program to write each line
in a file.

File.open("name","r") do |aFile|
  aFile.each_line() do |aLine|
    puts aLine
  end
end 

open might be defined like this

def File.open(name,mode)
  aFile = File.new(name,mode)
  yield aFile
  aFile.close()
end

In principal I like the idea.  From an 
implementaion standpoint the block that
follows the function is really just an 
anonymous function;

Anonymous functions have already been
suggested.

void Func(int b, int (*fp)(int));

Func(12,anon(a){ return a*a;});

Perhaps if the last parameter in a
functions parmeter list was a function 
pointer the anonymous function could be
specified after the ')'.

Func(12) anon(a)
{
    	return a*a;
}

This would make the anonymous function look a 
little cleaner if it was more than a couple of 
lines long.

"anderson" <anderson badmama.com.au> wrote in
news:b0ica3$21sj$1 digitaldaemon.com: 

 Yet again, another idea.
 
 I think it would be cool if you could program your own block
 statements. Often you need to have open/close statements (like with
 files). If you can force the user to call them in a certain order
 using programmable block statements, I think it would save a lot of
 bugs. 
 
 Of course the idea I present here is only a prototype.
 
 Class ABC
 {
     void open(char * FileName, block Enter)
     {
         if (Enter)
         {
             ...
         }
         else
         {
             ...
         }
     }
 }
 
 ...
 
 ABC x;
 
 x.open("filename")
 {
 
 } //Closes here
 
 You could also handle return types (if it had one). V would only be
 returned after open (enter) had completed.
 
 v = x.open("filename")
 {
 
 } //Closes here
 
 And you could also use the function as-per-normal where block =
 boolean. 
 
 x.open("filename", true)
 x.open("filename", false)
 
 PS - I would suppose there were lots of ways of syntax'ing this, I
 tried to choose an easily phaseable one.
 
 
Jan 20 2003
prev sibling parent Mark Evans <Mark_member pathlink.com> writes:
The Oz book covers such material.  What you are talking about relates to the
dataflow paradigm and also to threads.  Oz has a whole raft of capability
relating to threads, distributed stores that appear as one, etc.

Mark
Jan 20 2003