From: "David A. Black" Date: 2010-05-05T17:14:36+09:00 Subject: Re: for-in vs. map closures Hi -- On Wed, 5 May 2010, Josh Cheek wrote: > On Wed, May 5, 2010 at 1:35 AM, Mike Austin wrote: > >> I was experimenting with closures and JavaScript's and Ruby's >> behavior. Ruby seems to close over its arguments automatically if >> using map: >> >> [1, 2, 3].map { |n| lambda { n * n } }.map { |b| b.call() } # [1, 4, >> 9] >> >> But using "for" iteration, returns a different result: >> >> a = [] >> for n in [1, 2, 3] do a << lambda { n * n } end >> a.map { |b| b.call() } # [9, 9, 9] >> >> This is also the behavior in JavaScript, which frequently catches >> developers off guard when attaching event handlers to elements. >> >> Can anyone explain the difference? Is map creating a new anonymous >> function every iteration? >> >> Mike >> >> > I don't know, it seems like very peculiar behaviour. It does create new > lambdas every time, but strangely, the objects created within the block are > shared. > > a = Array.new > for s in %w(a b c) > s2 = s > a << lambda { [ s2 , s , s2.object_id ] } > end > > a.map { |b| b.call() } # => [["c", "c", 2148175880], ["c", "c", > 2148175880], ["c", "c", 2148175880]] > a[0].object_id # => 2148175860 > a[1].object_id # => 2148175840 > a[2].object_id # => 2148175820 for doesn't create a new local scope: >> defined?(b) => nil >> for a in [1]; b = 2; end => [1] >> b => 2 It's similar to if and friends in this respect. So s and s2 in your example are the same variables every time through the loop. David -- David A. Black, Senior Developer, Cyrus Innovation Inc. THE Ruby training with Black/Brown/McAnally COMPLEAT Coming to Chicago area, June 18-19, 2010! RUBYIST http://www.compleatrubyist.com