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.

There is an hackaround:

    auto arr=new ulong delegate()[5];

    foreach(i;0..arr.length){
        arr[i]=(j=>()=>j)(i);
    }

    writeln(arr.map!`a()`());

This prints [0, 1, 2, 3, 4] as expected, since we use another function to create a separate stack frame to store the value of `i`. A different way to implement that idea:

    auto arr=new ulong delegate()[5];

    foreach(i;0..arr.length){
        arr[i]={
            auto j=i;
            return ()=>j;
        }();
    }

    writeln(arr.map!`a()`());



Can this be fixed? *Should* this be fixed?

Discuss

Reply via email to