The magic behind foreach (was: Re: Descent 0.5.3 released)

Ary Borenszweig ary at esperanto.org.ar
Wed Jan 21 22:32:22 PST 2009


Ary Borenszweig wrote:
> Ary Borenszweig wrote:
>  > BCS wrote:
>  >> Reply to Robert,
>  >>
>  >>> That doesn't look entirely useless, especially for optimization.
>  >>> Perhaps hard to read, but easier than reading the assembly output ;-P!
>  >>>
>  >>
>  >> ditto; now that you have it might as well make it available.
>  >
>  > Ok, I'll work on it. :-)
> 
> I still have to work on some stuff, but...
> 
> Before:
> ---
> module main;
> 
> import std.stdio;
> 
> class Foo {
>     uint array[2];
> 
>     int opApply(int delegate(ref uint) dg) {
>         int result = 0;
> 
>         for(int i = 0; i < array.length; i++) {
>             result = dg(array[i]);
>             if(result)
>                 break;
>         }
>         return result;
>     }
> }
> 
> int main(char[][] args) {
>     Foo foo = new Foo();
>     foreach(x; foo) {
>         if (x == 3) {
>             break;
>         }
>         writefln("%s", x);
>     }
>     return 0;
> }
> ---
> 
> After:
> ---
> module main;
> 
> import object;
> import std.stdio;
> 
> class Foo: Object {
>     uint[2] array;
> 
>     int opApply(int delegate(ref uint) dg) {
>         assert(this, "null this");
>         {
>             int result = 0;
>             for(int i = 0; cast(uint) i < 2; i++) {
>                 result = dg(this.array[cast(uint) i]);
>                 if(result)
>                     break;
>             }
>             return result;
>         }
>     }
> }
> 
> int main(char[][] args) {
>     Foo foo = new Foo;
>     foo.opApply(delegate (uint __applyArg0) {
>         {
>             {
>                 uint x = __applyArg0;
>                 if(x == 3)
>                     return 1;
>                 writefln("%s", x);
>             }
>             return 0;
>         }
>     } );
>     return 0;
> }
> ---
> 
> Ummm... I was wondering... In every implemetation of opApply, after you 
> invoke the delegate you must check the result to see if it's non zero, 
> right? In that case, you must break the iteration.
> 
> If the compiler can transform a "foreach" into an opApply call, passing 
> the foreach body and converting breaks to "return 1" statements... can't 
> opApply be specified as:
> 
> int opApply(void delegate(ref uint) dg) { // note: delegate returns void
> }
> 
> and the compiler transforms the opApply signature to the one that's used 
> now, plus converting each dg call to a call and a check of return value 
>  != 0 and return 1 in that case?
> 
> Yes, yes, this is not trivial at all, but it's possible. And then D 
> programmers no longer have to make ifs and return magic numbers to make 
> foreach work. (think: do once in the compiler, eliminate thousands of 
> boilerplate codes in programs)
> 
> So basically:
> 
> ---
> int opApply(void delegate(ref uint) dg) {
>   for(int i = 0; i < array.length; i++) {
>     dg(array[i]);
> }
> ---
> 
> would be converted to:
> 
> 
> ---
> int opApply(void delegate(ref uint) dg) {

I mean:

int opApply(int delegate(ref uint) dg) {

>   for(int i = 0; i < array.length; i++) {
>     result = dg(array[i]);
>     if (result) return 1;
> }
> ---
> 
> What do you think?
> 
> (By the way, why opApply returns an int? What's the use of that?)



More information about the Digitalmars-d mailing list