opApply/opApplyReverse return value types

Bill Baxter dnewsgroup at billbaxter.com
Tue Oct 17 17:42:41 PDT 2006


Bill Baxter wrote:
> Max Samuha wrote:
>> The question might seem idle but why opApply/opApplyReverse return int
>> instead of bool, anyway?
> 
> Actually, why do they have to return anything?  It seems like it should 
> be possible to make this work:
> 
> void opApply(void delegate(inout ArgT) dg)
> {
>    for (int i=0; i<length; i++)
>    {
>       if (dg(array[i]))
>         break;
>    }
> }
> 
> I haven't totally grokked the code, but I see the magic is happening in 
> statement.c, ForeachStatement::semantic somewhere.  That function is 
> constructing the delegate that wraps the loop body.  I don't see why the 
> delegate wrapper can't just store the value it returns to me so I don't 
> have to keep track of it.  It seems weirdly low-level for me to have to 
> be the shephard of some value who's meaning is totally opaque to me.

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;
}

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?

--bb



More information about the Digitalmars-d-learn mailing list