foreach, an analogy

Bill Baxter dnewsgroup at billbaxter.com
Thu Oct 19 16:55:20 PDT 2006


Reiner Pope wrote:
> Walter Bright wrote:
>> Bruno Medeiros wrote:
>>> As of DMD now, the only advantage in 'foreach_reverse' is ephemerous: 
>>> it allows efficient reverse iteration of arrays.
>>
>> That's the most important use case.
>>
>>> But couldn't the compiler easily detect this:
>>>   foreach(Foo f; &fooarray.opApplyReverse) { ...
>>> and and compile it as if it were a:
>>>   foreach_reverse(Foo f; fooarray) { ...
>>
>> Yes, it could. But it looks like a hack. A little syntactic sugar 
>> makes a big difference.
> 
> Here's a better solution: allow trailing delegates, and define iteration 
> according to them, making user iteration first-class. Then, mandate that 
> arrays support forwards and backwards iteration using, eg, 'each' and 
> 'each_r' and the compiler can optimize such calls away:
> 
>  [0,1,2].each (i) writefln(i); // Prints 0 1 2
>  [0,1,2].each_r (i) writefln(i); // Prints 2 1 0
> 
> void random(int[] array, void print(int i, out IterationStatus v), inout 
> IterationStatus s) { /* define my own random iterator */ }
> 
>  [0,1,2].random (i) writefln(i); // Prints 0 2 1
> 
> You get the efficiency and an even nicer syntax.


Exactly.

 >>>   foreach(Foo f; &fooarray.opApplyReverse) { ...

looks like a hack because "foreach" doesn't really *do* anything there, 
it's the opApplyReverse that does all the work.  'foreach' is just 
standing there as a signal to the compiler that it should pass the 
following block as a delagate.  But Reiner is right.  The compiler 
doesn't really need that hint, because just using a trailing delegate is 
already unambiguous, and is much cleaner, and is a more general concept, 
and at the same time it requires no magic methods 
(opApply/opApplyReverse) and no keywords (foreach/foreach_reverse).

If Reiner's suggestion were in there, I'd could probably accept

    foreach(i; collection) { body }
    foreach_reverse(i; collection) {body)

as aliases for

    collection.opApply(i) { body }
    collection.opApplyReverse(i) { body }

But I probably wouldn't use it.  I'd probably go with a convention more 
like Reiner's and do

    collection.foreach(i) { body }

Look, I'm not a Ruby programmer.  What I know about Ruby blocks I 
learned in the past two days.  But the instant I read the explanation of 
how they work, it was like "yes! that's it! it makes perfect sense. 
THAT's the way to do it."  Riener's proposal basically is Ruby blocks 
for D.

Before, when only arrays and objects were allowed in foreach, it kind of 
made sense.   I can totally see why foreach works the way it does.  But 
with the ability to pass an arbitrary delegate-accepting function in 
there, the 'foreach' becomes like a vestigial tail.  It's just not 
needed anymore.  But the current approach is like letting that vestigial 
tail wag the entire dog.

--bb



More information about the Digitalmars-d-announce mailing list