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.

Reply via email to