I'm reading the Metaprogramming section of Programming Ruby 1.9 and I'm having trouble understanding what's going on internally between class_eval
/class_exec
vs. instance_eval
/instance_exec
.
So first of all, my understanding is that def
adds a method to the method table of self
(the class object):
class A puts self # => A def foo; 42; end # added to the method table of self, so becomes an instance method end A.new.foo # => 42
And if we use class_eval
, we get the same behavior:
A.class_eval do puts self # => A def bar; 42; end # same as above end A.new.bar # => 42
But somehow in the instance_eval
case, things are different:
A.instance_eval do puts self # => A def baz; 42; end # added to the method table of an anonymous # singleton class of self, so becomes a class method end puts A.baz # => 42 s = 'string' s.instance_eval do ... end # same behavior, so now def creates an instance method
So I understand the functional difference between class_eval
and instance_eval
.
But the contexts inside the class_eval
and instance_eval
blocks look exactly the same to me -- in particular, self
points to the same object, and the local_variables
are the same. So what's going on inside the blocks (internally) that's making def
act different?
Is there some piece of documentation I could read? The RDoc for instance_eval and class_eval doesn't help. Looking at the source, instance_eval seems to set up a singleton class object whereas class_eval doesn't -- but is this difference visible outside the C code, on the Ruby level?
class_eval(array_second) adds the method second to any instance of Array by passing a String that will be evaluated in the context of the class Array . The call to String. class_eval with a block will evaluate the content of the block in the context of the class String .
The instance_eval method defines a method for one object only, whereas the class_eval method defines it for ALL objects or instances of a class.
I think your confusion comes from the fact that def does not depend on the current self, you might think about it as being a "current class" that has it's own rules.
Following your examples:
class A # defs here go to A puts self # => A class << self #defs here go to A's eigenclass end end A.class_eval do #defs here go to A end A.instance_eval do #defs here go to A's eigenclass end s = "Hello World" class << s #defs here go to s's eigenclass end
Here's the portion of the chapter that talks about the issue and it's pretty clear about the behaviour
class_eval and instance_eval both set self for the duration of the block. However, they differ in the way they set up the environment for method definition. class_eval sets things up as if you were in the body of a class definition, so method definitions will define instance methods In contrast, calling instance_eval on a class acts as if you were working inside the singleton class of self. Therefore, any methods you define will become class methods.
The only thing I think is worth adding is that you can call instance_eval in any object, not just classes, and the behaviour doesn't change but has different consequences.
Some relevant reading:
Ruby: instance_eval and class_eval method definitions
Chapter 4 of this most excelent series
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With