Closures and loop scope

Timon Gehr timon.gehr at gmx.ch
Tue Jun 4 13:52:27 PDT 2013


On 06/04/2013 09:19 PM, Idan Arye wrote:
> Consider the following code. What will it print?
>
>      auto arr=new ulong delegate()[5];
>
>      foreach(i;0..arr.length){
>          arr[i]=()=>i;
>      }
>
>      writeln(arr.map!`a()`());
>
> It is natural to expect that it will print [0, 1, 2, 3, 4], but it
> actually prints [5, 5, 5, 5, 5]. The reason is obvious - all the
> delegates refer to the same `i` in their closures, and at the end of the
> loop that `i` is set to `5`.
>
> ...

It is not that obvious. They refer to different i's that happen to 
reside at the same place in the stack frame. It's a bug.

It is more obvious that it is a bug given this code snippet:

import std.stdio, std.algorithm;

void main(){
     auto arr=new ulong delegate()[5];
     foreach(immutable i;0..arr.length){
          arr[i]={auto j=i;return {assert(j==i); return i;};}();
     }
     writeln(arr.map!`a()`());
}

As you can see, 'i' mutates even though it is declared immutable.

>...

Yes. Yes.

http://d.puremagic.com/issues/show_bug.cgi?id=2043


More information about the Digitalmars-d mailing list