Closures and loop scope
Nick Sabalausky
SeeWebsiteToContactMe at semitwist.com
Tue Jun 4 14:57:39 PDT 2013
On Tue, 04 Jun 2013 22:52:27 +0200
Timon Gehr <timon.gehr at gmx.ch> wrote:
> On 06/04/2013 09:19 PM, 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`.
> >
> > ...
>
> It is not that obvious. They refer to different i's that happen to
> reside at the same place in the stack frame. It's a bug.
>
> It is more obvious that it is a bug given this code snippet:
>
> import std.stdio, std.algorithm;
>
> void main(){
> auto arr=new ulong delegate()[5];
> foreach(immutable i;0..arr.length){
> arr[i]={auto j=i;return {assert(j==i); return i;};}();
> }
> writeln(arr.map!`a()`());
> }
>
> As you can see, 'i' mutates even though it is declared immutable.
>
Keep in mind that this exhibits the same "mutating immutable" behavior:
// Prints 0, 1, 2, 3, 4, even though i is immutable
foreach(immutable i; 0..5){
writeln(i);
It's questionable as to whether that's really a problem. And even if it
is a problem, it would *only* be because you make i immutable. So
this is irrelevant to the OP's examples because:
1. He didn't use immutable, and
2. A delegate is *expected* to read the values inside its closure at
the time of delegate *invocation*, not at the time of delegate creation.
> >...
>
> Yes. Yes.
>
> http://d.puremagic.com/issues/show_bug.cgi?id=2043
That refers to a local defined within the loop, not the iteration
variable itself, which is different from the OP. Also, it's
questionable that there's any problem there *other* than the immutable
stuff.
More information about the Digitalmars-d
mailing list