Closures and loop scope

Idan Arye GenericNPC at gmail.com
Tue Jun 4 12:19:56 PDT 2013


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


More information about the Digitalmars-d mailing list