Although I have encountered this problem in Python, it is easier to explain it in Ruby. In Ruby, there are many ways to traverse an array, and the two most commonly used are for and each:
arr = [' A ', ' B ', ' C ']
Arr.each {|e|
Puts E
}
For E in Arr
Puts E
End
Usually I prefer the latter, it seems to be nice to write, but the former should be a little bit quicker in terms of efficiency, since the latter is actually called a lambda function for each element during traversal, although it is generally not obvious, but setting the context and invoking the function does have overhead, Especially in dynamic languages (regardless of JIT inline optimization). But this time the problem is not performance. It does, however, have to do with "each to create a new scope for every element and the for is not".
Look at the following code:
arr = [' A ', ' B ', ' C ']
H1 = Hash.new
H2 = Hash.new
Arr.each {|e|
H1[e] = lambda {e+ '! '}
}
For E in Arr
H2[e] = lambda {e+ '! '}
End
h1[' A '].call # =>?
h2[' A '].call # =>?
What do two call distinctions get? Should have guessed it already? respectively, ' a! ' and ' c! ', the latter is ' c! ' because the for does not recreate a scope at every step of the loop, so the closure of the three lambda references the same variable, which was assigned the last time ' C ', causing the Consequences.
The problem is actually a paragraph in a small program I wrote in Python, and the code looks like this:
For prop in Public_props:
SetAttr (proxy, ' get_%s '%prop, Lambda:self.get_prop (prop))
Where proxy is a proxy object that I provide, exposing some of the exposed properties of self, because to restrict access to non-public properties, I do not want to deposit any references to self in this proxy, otherwise, in Python without access restrictions, through a similar PR Oxy._orig_self.some_private_prop way to access is easy. So finally chose the above approach.
Unfortunately, because, as we just said, the for does not create a scope individually each time, so closure is all referenced to the same variable, causing all the property values to be taken out of the last attribute. See such a strange bug, if it is in C + +, I am sure to suspect the memory or the problem of the pointer. But thought for a long time to finally suddenly realize! But there's no Ruby in Python that's easy to use, and the lambda is pretty chicken, so it's finally solved by defining a local function:
def proxy_prop (name):
SetAttr (proxy, ' get_%s '%prop, Lambda:self.get_prop (name)
For prop in Public_props:
Proxy_prop (prop)
Finally, let's say that for the previous Ruby example, if you reverse the order of each and for, you get a different result:
arr = [' A ', ' B ', ' C ']
H1 = Hash.new
H2 = Hash.new
For E in Arr
H2[e] = lambda {e+ '! '}
End
Arr.each {|e|
H1[e] = lambda {e+ '! '}
}
h1[' A '].call # => ' c! '
h2[' A '].call # => ' c! '
Now two of them are ' c! '! This is because the parameters of the block in the implementation of Ruby 1.8 can be assigned to anything, such as a local variable or a global variable, rather than as simple as the parameter of a lambda function in the usual sense. Because the previous for statement creates an e as a local variable in the current scope, each is assigned directly to the local variable so that each reference becomes the same thing, causing a hidden Bug!
Thankfully, this "feature" of block has been removed from Ruby 1.9, and block parameters are only normal parameters, so there is no such problem. Hope 1.9 popularization as soon as possible!