Delegate, scope and associative array

Rene Zwanenburg via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Mon Jun 2 16:43:58 PDT 2014


On Monday, 2 June 2014 at 20:09:12 UTC, Edwin van Leeuwen wrote:
> I'm probably missing something basic, but I am confused by what 
> is going on in the following code.
>
> unittest {
>     size_t delegate()[size_t] events;
>     foreach( i; 1..4 ) {
>         events[i] = { return i; };
>     }
>     writeln( events[1]() ); // This outputs 3
>     assert( events[1]() == 1 );
> }
>
> I thought that i should be copied from the local scope and 
> therefore when I call events[1]() the return value should be 1, 
> but in this case it is 3 (it always seems to be the last value 
> of i in the loop).
>
> Cheers, Edwin

Yeah this is a known problem. At the moment the foreach loop is 
internally rewritten to something like

int i = 1;
while(i < 4)
{
   // foreach loop body

   ++i;
}

While it usually would be preferrable if it were rewritten as

int __compilergeneratedname = 1;
while(__compilergeneratedname < 4)
{
   auto i = __compilergeneratedname++;

   // foreach loop body
}

With the current approach every delegate refers to the same 
variable. Another problem is that it's possible to alter the 
iteration index from inside the foreach body.

As you may have guessed, a workaround is to copy the iteration 
variable yourself:

unittest {
     size_t delegate()[size_t] events;
     foreach(_i; 1..4 ) {
         auto i = _i;
         events[i] = { return i; };
     }
     assert( events[1]() == 1 );
}

This should work though it's less than ideal. There is an open 
bug report:
https://issues.dlang.org/show_bug.cgi?id=8621


More information about the Digitalmars-d-learn mailing list