www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Nested functions as delegated iterators

reply Daan Oosterveld <daan.oosterveld home.nl> writes:
Proposal:

To make use of the powerfull delegate and nested function features, a 
change in syntax could simplify the usage of these functions. These 
could then be used as iterators.

By combining delegates, iterators and nested functions the compiler 
changes should remain minimal. A simple substitution should be enough. 
As an example we will take a simple class called Mapping which maps 
char[] to char[]. The Mapping class has to iterators: each and filter.

class Mapping
{
     void filter ( bool delegate( char[] key, char[] value) dg )
     void each( void delegate( char[] key, char[] value) dg )
}

Then we could write in a main function:

Mapping m = new Mapping( mapping );
bool my_iterator(char[] key, char[] value) {
     return key == value;
}
m.filter( &my_iterator );

void my_dump_iterator(char[] key, char[] value) {
     printf("key: %.*s value: %.*s\n", key, value);
}
m.each( &my_dump_iterator );

But this is very tidious, because you have got to invent names each 
time. A nicer approuch would be:

m.filter() thru (char[] key, char[] value) { return key == value; }
m.each() thru (char[] key, char[] value) {
	printf("key: %.*s value: %.*s\n", key, value);
}

Which is also easier to read because the bodies follow the iterator.

The compiler can find the right iterator functions by appending the 
delegate to the argument list. The return value is deduced from the 
iterator delegate function. And a nested function could be created as above.

You might recognise these constructs from scheme or ruby, thanks to 
nested functions and delegates it is also possible in D. ;)

Another nice construct:

File.open("file.txt") thru ( File f ) {
     ... do things while file is open ...
} // file is closed after body is executed.

I would have used the "with" keyword if it was not occupied ;) If anyone 
can think of a better one?

Daan Oosterveld
Jan 25 2005
next sibling parent reply "Ben Hinkle" <bhinkle mathworks.com> writes:
"Daan Oosterveld" <daan.oosterveld home.nl> wrote in message 
news:ct65na$29r3$1 digitaldaemon.com...
 Proposal:

 To make use of the powerfull delegate and nested function features, a 
 change in syntax could simplify the usage of these functions. These could 
 then be used as iterators.

 By combining delegates, iterators and nested functions the compiler 
 changes should remain minimal. A simple substitution should be enough. As 
 an example we will take a simple class called Mapping which maps char[] to 
 char[]. The Mapping class has to iterators: each and filter.

 class Mapping
 {
     void filter ( bool delegate( char[] key, char[] value) dg )
     void each( void delegate( char[] key, char[] value) dg )
 }

 Then we could write in a main function:

 Mapping m = new Mapping( mapping );
 bool my_iterator(char[] key, char[] value) {
     return key == value;
 }
 m.filter( &my_iterator );

 void my_dump_iterator(char[] key, char[] value) {
     printf("key: %.*s value: %.*s\n", key, value);
 }
 m.each( &my_dump_iterator );

 But this is very tidious, because you have got to invent names each time.
Technically one doesn't have to invent names since currently one can write anonymous delegates: m.filter(delegate bool(char[] key, char[] value) {return key == value;} ); See http://www.digitalmars.com/d/expression.html#FunctionLiteral The syntax ends up looking pretty similar to your proposal. [snip]
Jan 25 2005
parent Daan Oosterveld <daan.oosterveld home.nl> writes:
Ben Hinkle schreef:
 "Daan Oosterveld" <daan.oosterveld home.nl> wrote in message 
 news:ct65na$29r3$1 digitaldaemon.com...
 
Proposal:

To make use of the powerfull delegate and nested function features, a 
change in syntax could simplify the usage of these functions. These could 
then be used as iterators.

By combining delegates, iterators and nested functions the compiler 
changes should remain minimal. A simple substitution should be enough. As 
an example we will take a simple class called Mapping which maps char[] to 
char[]. The Mapping class has to iterators: each and filter.

class Mapping
{
    void filter ( bool delegate( char[] key, char[] value) dg )
    void each( void delegate( char[] key, char[] value) dg )
}

Then we could write in a main function:

Mapping m = new Mapping( mapping );
bool my_iterator(char[] key, char[] value) {
    return key == value;
}
m.filter( &my_iterator );

void my_dump_iterator(char[] key, char[] value) {
    printf("key: %.*s value: %.*s\n", key, value);
}
m.each( &my_dump_iterator );

But this is very tidious, because you have got to invent names each time.
Technically one doesn't have to invent names since currently one can write anonymous delegates: m.filter(delegate bool(char[] key, char[] value) {return key == value;} ); See http://www.digitalmars.com/d/expression.html#FunctionLiteral The syntax ends up looking pretty similar to your proposal. [snip]
Hmm, I overlooked that part of the documentation. GREAT! But still my C/C++ background doesn't like to put {} inside () because it looks ugly and it is cluttering. ;) Same for C (and D) we use variadic functions to reduce clutter. We don't have to write things like this: printf("key: %.*s value: %.*s\n", [ cast(void *) key, cast(void *) value ]); or: printf("key: %.*s ", key ); printf("value: %.*s\n", value ); Which also reduces clutter and makes the source more readable. Same thing for delegate literals: m.filter( delegate bool(char[] key, char[] value) { return key == value; } ); looks more cluttered as this: m.filter() thru (char[] key, char[] value) {return key == value;} (and we don't even need funky function calls like variadic functions need to decrypt the argument list) With an more complex program the clutter becomes a mess: RegExp ereg = new RegExp("^import",""); File.open("textfile", delegate (File f) { f.each_line( delegate (char[] l) { if (ereg.match( l )) { ... extract import statements ... } } ); } ); It is difficult to see where the ");" comes from. Whereas writen with a different syntax the program is more readable. RegExp ereg = new RegExp("^import",""); File.open("textfile") thru (File f) { f.each_line() thru (char[] l) { if (ereg.match( l )) { ... extract import statements ... } } } Given the right classes and member functions writing small programs becomes very easy (and nice to look at) Daan
Jan 26 2005
prev sibling parent Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
Daan Oosterveld wrote:
 Proposal:
 
 To make use of the powerfull delegate and nested function features, a 
 change in syntax could simplify the usage of these functions. These 
 could then be used as iterators.
 
 By combining delegates, iterators and nested functions the compiler 
 changes should remain minimal. A simple substitution should be enough. 
 As an example we will take a simple class called Mapping which maps 
 char[] to char[]. The Mapping class has to iterators: each and filter.
 
 class Mapping
 {
     void filter ( bool delegate( char[] key, char[] value) dg )
     void each( void delegate( char[] key, char[] value) dg )
 }
 
 Then we could write in a main function:
 
 Mapping m = new Mapping( mapping );
 bool my_iterator(char[] key, char[] value) {
     return key == value;
 }
 m.filter( &my_iterator );
 
 void my_dump_iterator(char[] key, char[] value) {
     printf("key: %.*s value: %.*s\n", key, value);
 }
 m.each( &my_dump_iterator );
 
 But this is very tidious, because you have got to invent names each 
 time. A nicer approuch would be:
 
 m.filter() thru (char[] key, char[] value) { return key == value; }
 m.each() thru (char[] key, char[] value) {
     printf("key: %.*s value: %.*s\n", key, value);
 }
I believe that what you are trying to do can be done already, with delegate literals! m.filter(delegate bool(char[] key,char[] value) { return key == value; } ); m.each(delegate void(char[] key,char[] value) { printf("key: %.*s value: *.*s\n", key,value); } );
Jan 25 2005