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