opApply and that int

Bill Baxter dnewsgroup at billbaxter.com
Fri Jan 4 09:14:01 PST 2008


Bill Baxter wrote:
> I know we've been through this before but I don't recall the conclusion.
> 
> Why do we have to pass an int through our opApply functions.
> 
> Given an object.opApply that takes a delegate that takes a ref T,
> and code like this:
> 
> foreach(T x; object) {
>      if (x) break;
>      if (condition) return Something;
>      do_something;
> }
> 
> the compiler transforms that into something like this:
> 
> RType _fn_ret; // (RType is return type of enclosing function)
> int _loop_body(ref T x)
> {
>    if (x) return BREAK;
>    if (condition) { _fn_ret = Something; } return RETURN;
>    do_something;
>    return 0;
> }
> int _ret = object.opApply(&_loop_body));
> if (_ret==RETURN) return;
> else if (_ret==GOTO) goto ??;
> // maybe some other cases...
> 
> 
> My question is this: _loop_body and the caller of opApply share the same 
> enclosing scope, so why not stick the return code in a local variable 
> both can see?  It already seems to do that that for return values (as 
> far as I can tell from reading dmd/src/dmd/statement.c).  So why not do 
> it for the main return code too and generate code like this:
> 
> RType _fn_ret;
> int _ret = 0;
> void _loop_body(ref T x)
> {
>    _ret = 0;
>    if (x) { _ret = BREAK; return; }
>    if (condition) { _fn_ret = Something; _ret = RETURN; return; }
>    do_something;
> }
> object.opApply(&_loop_body));
> if (_ret==RETURN) return;
> else if (_ret==GOTO) goto ??;
> // maybe some other cases...
> 
> 
> Why oh why does that int have to go traipsing through *my* opApply?
> 
> --bb

Ok, Jason poked me into realizing that I completely forgot that the 
user's opApply has to know to return when the loop body does a break or 
something.  So with what I just proposed it would still have to check 
for a non-zero return code, *BUT* it wouldn't have to return it to the 
caller.  So opApplys could become:

      void opApply(int delegate(ref T) loop_body) {
            for(/*x in elements*/) {
                 if (loop_body(x)) return;
            }
      }

At least then users don't have to handle radioactive materials.

Still I'd love to get rid of that int in front of the delegate too and 
just have something like:

      void opApply(void delegate(ref T) loop_body) {
            for(/*x in elements*/) {
                 loop_body(x);
                 yield();
            }
      }

The trouble is figuring out how to make yield do its magic.
Macros I guess will make it possible to have yield actually return from 
the function.  But I don't see a good way to communicate the current 
loop state to yield().  Yield could maybe know about the stack layouts 
and the code that calls opApply could be careful to put the "int _ret" 
variable in a place on the stack that yield() could always reach up to 
find it.  Yield would be doing tricky non-portable stuff, but the idea 
is it would be included as part of something low-level like object.d, so 
non-portable would be ok.  Unfortunately if you call yield in a 
non-opApply callback situation it could just do bogus stuff and probably 
couldn't even warn you that what you were doing was bogus.

--bb


More information about the Digitalmars-d-learn mailing list