About foreach loops

Timon Gehr timon.gehr at gmx.ch
Wed Jun 15 12:05:25 PDT 2011


Steven Schveighoffer wrote:
> I've seen several cases where the syntactic sugar does not work.
>
> two things:
>
> if the compiler detects you never change i, then it can eliminate the
> temporary variable.

It could. Does DMD do that? Let's see:
import std.stdio;

void main(){
    foreach(_i;0..100){
        writeln(i);
    }
}

void main(){
    foreach(_i;0..100){
        const i=_i;
        writeln(i);
    }
}

dmd test
1 mov    -0x8(%rbp),%edi

2 mov    -0x8(%rbp),%ecx
2 mov    %rcx,%rdi

dmd test -O

Identical. Nice. Now for something more complex:

import std.stdio;

struct S{
    int i;
    this(this){writeln("postblit");}
    void opUnary(string op:"++")(){++i;}
}

void main(){
    foreach(_i;S(0)..S(2)){
        //auto i=_i;
        alias _i i;
    }
}

dmd test -O

With the alias i:

With the auto i:
postblit
postblit


=> Not optimized away, even though it could remove the whole loop.

> We should favor the case which is most useful, not the one which is
> simplest to implement.  If you want surprising behavior, use a for loop.

Also if I want guaranteed efficient looping. :o)

>
> When I see foreach(i; xxx), I think i should take on every value contained
> in xxx, whether that be a range, array, or something else.  Being able to
> change the elements iterated during the loop is surprising to say the
> least.
>
> Also, think about this:
>
> foreach(i; 0..10)
> {
>     i -= 2;
> }
>
> This is a loop that counts *down* to int.min from -1.  The idea that this
> should be *expected* behavior is just ludicrous to me.
>
> -Steve

Absolutely. Regarding consistency, it is pretty clear that it should be changed.


Timon


More information about the Digitalmars-d mailing list