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