Closures and loop scope

Yota yotaxp at thatGoogleMailThing.com
Thu Sep 19 09:39:13 PDT 2013


I just ran into the problem myself, and it really caught me off 
guard.

import std.stdio, core.thread;
void main() {
     foreach (i; 0..3) {
         immutable ii = i; // Copy for good measure?
         writeln("Main: ", ii);
         auto t = new Thread({
             writeln("Worker Start: ", ii);
             Thread.sleep(dur!"msecs"(1));
             writeln("Worker End: ", ii);
         });
         t.start();
     }
}

  Output:
Main: 0
Main: 1
Worker Start: 1
Main: 2
Worker Start: 2
Worker Start: 2
Worker End: 2
Worker End: 2
Worker End: 2

I caught on that the problem has to do with capturing stack 
variables that are going out of scope, but this is resulting a 
mutating immutable, without subverting the type system, and 
without a complaint from the compiler. (First iteration, 'ii' is 
captured while 0.  The captured 'ii' is then 1 when the thread 
begins, and 2 when it ends.)  This seems like a major problem in 
the type system, without even being a problem with the type 
system.

The following was suggested as a means to capture by value:

On Tuesday, 4 June 2013 at 19:19:57 UTC, Idan Arye wrote:
> 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 indeed appears to work, but... why?  From the looks of it, 
it is doing the exact same thing.  It is capturing a local stack 
variable that immediately goes out of scope.  Why isn't the extra 
stack frame being overwritten each iteration?  Also, that 
anonymous function really looks like something that the compiler 
would inline, so is there even an extra stack frame?  I think I 
see why Idan called it a 'hackaround'.


I gather two things from this:

1. We really need a legit way to force capture-by-value on a 
variable by variable basis.  (Unless there's already another way. 
  Anyone?)

2. Why are immutable local variables not ALWAYS captured by 
value?  It's not like they are expected to change at all in the 
first place.  This would at least fix the promise that the type 
system makes regarding immutables. (Well... until pointers to 
immutables on the stack come into play.)


More information about the Digitalmars-d mailing list