opApply/opApplyReverse return value types

Jarrett Billingsley kb3ctd2 at yahoo.com
Tue Oct 17 18:58:02 PDT 2006


"Bill Baxter" <dnewsgroup at billbaxter.com> wrote in message 
news:eh3taa$1c98$1 at digitaldaemon.com...
> I tried a little more to figure out statement.c, but it's definitely over 
> my head for now without studying more about the internals of the compiler. 
> Still, I'd like to understand how this foreach/opApply business works, so 
> let me explain how I think it works in principle, and hopefully someone 
> can tell me where I'm wrong.
>
> I'm thinking that basically when you write:
>
>   foreach( T val; aggregate )
>      /loopBody/
>
> Conceptually what happens is that d makes some wrapper around your loop 
> body:
>
> class loopWrapper(T)
> {
>     int doOneLoop(T val)
>     {
>        /setup code/
>        /loopBody/
>        /cleanup code/
>        return ret;
>     }
> }
>
> And then it calls your opApply passing it a delegate to that wrapper.
>
>    wrap = new loopWrapper();
>    int ret = aggregate.opApply( &wrap.doOneLoop );
>
> Then my opApply does something like the standard:
>
> int opApply(int delegate(inout ArgT) doOneLoop)
> {
>    int ret;
>    for (int i=0; i<length; i++)
>    {
>       ret = doOneLoop(myArray[i]);
>       if (ret)
>         break;
>    }
>    return ret;
> }

You're right, although it does it a bit more efficiently by just turning 
your loop body into a  nested function, and translating all "break"s into 
"return 1"s and "continue"s into "return 0"s and sticks a "return 0" at the 
end.  So..

foreach(int x; a)
{
    if(x == 6)
        break;

    if(x == 3)
        continue;

    writefln(x);
}

Becomes:

a.opApply(delegate int(inout int x)
{
    if(x == 6)
        return 1;

    if(x == 3)
        return 0;

    writefln(x);
    return 0;
});

In fact, the latter is entirely valid code and works fine.

> But D owns the loopWrapper and controls what goes into doOneLoop's /setup 
> code/ and /cleanup code/, so D should know what its return value is 
> without having to ask the aggregate to return it.    Why not stash the 
> return value in the loopWrapper so the user doesn't have to worry about 
> it?  Like this:
>
> class loopWrapper(T)
> {
>     void doOneLoop(T val)
>     {
>        /setup code/
>        /loopBody/
>        /cleanup code/
>        retCode = ret;  // ADDED
>        return;
>     }
>     int retCode;  // ADDED
> }
>
> Then D could just get the return code from the wrapper:
>
>    wrap = new loopWrapper();
>    aggregate.opApply( &wrap.doOneLoop );
>    int ret = wrap.retCode;
>
> and not bother every opApply function with having to handle it with boiler 
> plate code that a) they can easily mess up, and b) obfuscates the 
> underlying idea.
>
> So why wouldn't that work?

You know, out of curiosity:

class A
{
 int[] arr;

 this()
 {
  arr = new int[10];

  foreach(int i, inout int v; arr)
   v = i;
 }

 int opApply(int delegate(inout int) dg)
 {
  foreach(int v; arr)
  {
   if(dg(v))
    break;
  }

  return -49;
 }
}

void main()
{
 A a = new A();

 foreach(int v; a)
  writefln(v);

 writefln("done");
}

This works fine.  I am returning -49 from opApply and it works fine.  I can 
return 0 from opApply and it works fine.  I honestly have no idea what the 
return from opApply is for. 





More information about the Digitalmars-d-learn mailing list