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