Closures and loop scope

Nick Sabalausky SeeWebsiteToContactMe at semitwist.com
Tue Jun 4 14:03:00 PDT 2013


On Tue, 04 Jun 2013 21:19:56 +0200
"Idan Arye" <GenericNPC at gmail.com> 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`.
> 

I think the problem is simply a misunderstanding of closures.

Consider this:

    int a = 2;
    auto dg = () => a;
    a = 3;
    
    // This prints 3
    writeln(dg());
    
    // Now this prints 5
    a = 5;
    writeln(dg());

The thing to keep in mind is that closures are *not* evaluated at the
point of creation (otherwise they may as well not be written as a
delegate at all). They're evaluated at the point of invocation. And
that's the whole point: to say "Ok program, I want you to *hold on* to
this set of instructions for now...ignore them right now, but I'll tell
you when I want you to 'open the envelope' and look at it".

In other words, the scope captured by a delegate is *by reference*, not
by value. It's the *same* scope, not a snapshot copy of the scope.

So when you put the delegate creation in a loop:

    foreach(a; iota(0..6))
        dg = () => a;

It *is* expected that you're *not* sticking 0, 1, 2, 3, etc inside the
delegate. That's because you're not evaluating "a" *at all* here,
you're just crerates a delegate that *refers* to "a" itself. You're
just creating the exact same delegate five times. In other words:

You're just saying:
Store the following set of instructions into 'dg': "Read the value of
'a' and then return it."

You're *not* saying:
Read the value of 'a' and *then* create a delegate that returns that
value.




More information about the Digitalmars-d mailing list