Closures and loop scope

JS js.mdnq at gmail.com
Tue Jul 23 06:37:24 PDT 2013


On Tuesday, 4 June 2013 at 19:19:57 UTC, 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`.
>
> While this makes some sense when you consider how the closures 
> are implemented, it is still not what you expect from that 
> code. `i` is supposed to be local to each iteration of the 
> loop, and here it "leaks" between the iterations.
>

The same problem exists in C#.

The issue is rather simple but I'll make it more clear:

The delegates are called AFTER the for loop(since you are storing 
them in an array, presumably to use them later). i = 5(or even 
undetermined) after the loop, hence the behavior is correct.

It is wrong to use a local variable inside a delegate when the 
delegate is called outside the scope of that variable. This 
should technically be an error as it is undefined behavior.

I imagine the compiler isn't smart enough to know that you are 
storing delegates to be used outside the scope of i.

Basically when the lifetime of a variable has ended all 
references to it(such as  in a delegate) are invalid. Only 
delegate invocation referencing live variables will be valid.


More information about the Digitalmars-d mailing list