Thread overview
Nested functions as delegated iterators
Jan 25, 2005
Daan Oosterveld
Jan 25, 2005
Ben Hinkle
Jan 26, 2005
Daan Oosterveld
Jan 25, 2005
Russ Lewis
January 25, 2005
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
January 25, 2005
"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]


January 25, 2005
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); }
      );

January 26, 2005
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