Consider
# At the top level self is a specific top-level object
def foo
# This method will be a singleton method of the top-level object
# It's installed in the method-hash of the singleton-class of the
top level object.
end
# when methods are required in reponse to a send, a search is
instituted starting with the receivers klass (i.e. it's true class
which may
# be a singleton class which is put on the search chain ahead of the
objects 'birth' class.
# Classes, including singleton classes, have a method hash which maps
method names to methods.
# For purposes of this post, I'm going to say that classes contain the
methods of their instances via this method hash.
Foo.instance_eval do
# self is now the class object named Foo
def foo2
# This method will be a singleton method of Foo
# it gets installed in the method-hash of the singleton-class of Foo
end
end
Now the fact that foo2 is a singleton method is a side-effect of
sorts. It's really a class method of Foo.
It get's reported as a singleton class because it's 'contained' in a
singleton class. This is true of normal class methods for example:
Array.singleton_methods => [""]
Array.methods(false) => [""]
Now all this begged a question in my mind. That is, what's the
difference between instance_eval and class_eval (with its alias
module_eval). A little digging in the 1.8.6 MRI code reveals that
both use the same underlying code, but the inner c function
specific_eval (in eval.c) takes both a klass and a self argument.
Both rb_object_instance_eval (the code behind Kernel#instance_eval)
and rb_mod_module_eval (the code behind both Module#module_eval and
Module#class_eval) set the self argument to the receiver.
rb_obj_instance_eval sets the klass argument to the singleton_class of
the receiver (creating it if it doesn't already exist), unless the
receiver is an immediate object (a Fixnum, or nil, true, or false) in
which case it sets klass to nil.
rb_mod_module_eval sets the klass argument to the receiver which must
be a module or a class. It's the klass argument of specific_eval
which ultimately determines the destination of a method defined by
def;end in the block.
···
On Nov 16, 2007 5:59 PM, Greg Weeks <greg.weeks@arm.com> wrote:
> It changes 'self' to the receiver, for the duration of the block.
> It only affects the execution context by binding self to the instance
And the value of self affects:
- explicit uses of "self"
- naked message-sends
- instance and class variable access
Anything else?
Hmmm. This is still a mystery:
class Foo
end
Foo.instance_eval do
def foo ; "foo" ; end
end
p Foo.singleton_methods -> ["foo"]
The "def" should have gone into the top-level environment, but it went
into <<Foo instead. So my hat is still out. (But I'm a lot better off
than I was.)
--
Rick DeNatale
My blog on Ruby
http://talklikeaduck.denhaven2.com/