opApply/opApplyReverse return value types

Bill Baxter dnewsgroup at billbaxter.com
Tue Oct 17 19:31:25 PDT 2006


Jarrett Billingsley wrote:
> "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. 

Wow, you're right!  Maybe it's for the vague and mysterious "future"??

I wonder if it's really legit?

--bb




More information about the Digitalmars-d-learn mailing list