On Tue, 04 Jun 2013 21:19:56 +0200 "Idan Arye" <generic...@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.