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.
P.S. I added this example as a gist, you can read it here https://gist.github.com/868310
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.
···
On Mon, Mar 14, 2011 at 11:20 AM, lucapette <lucapette@gmail.com> 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.
Thank you for the reply. It's a perfect explanation for me. There is always something new to learn with Ruby. That's why I love it so much.