From: "Jesús Gabriel y Galán" Date: 2011-03-14T19:32:39+09:00 Subject: Re: Unespected result of define_method with "for" and "each" On Mon, Mar 14, 2011 at 11:20 AM, lucapette wrote: > Hi everyone, > > I was trying to define instance methods on a class based on an given array of strings. I run into different results using two different types of iteration. I can't understand the resulting behaviour just in a case, the following piece of code will be more meaningful than words: > > class Toy > > end > > %w{e1 e2}.each { |m| >    Toy.class_eval do >        define_method m do >            puts m >        end >    end > } > > for m in %w{u1 u2} >    Toy.class_eval do >        define_method m do >            puts m >        end >    end > end > > p=Toy.new > > puts p.e1 # ok > puts p.e2 # ok > puts p.u1 # WTF > puts p.u2 # ok > > I tested it with ruby 1.8.7 and with 1.9.2 and I get the same results . Obviously, the third result is the only I don't understand :). It seems that define_method defers the evaluation of "m" object when used with a for. > > I'm relatively new to Ruby and  maybe this is the expected behaviour. I would like to understand the difference between the to version, > thank you. It is expected, and the reason is the way closures work and the fact that the block passed to "each" is a new scope, while the body of the "for" is not a new scope. In the first case, the closures created by class_eval and define_method close over a local variable m, *which is different for each iteration*, because it is local to the block passed to each, and the block is a new scope, so every iteration creates a new variable m. In the second case, though, the m is a local variable but to the whole script, it's not local to the body of the for, since the body of the for does not create a new scope. And so, in this case the closures created by class_eval and define_method close over a single variable m, which after all is said and done refers to the string "u2", so when you are calling the method u1, it returns this string. Jesus.