From: Peter Vandenabeele Date: 2010-12-05T04:56:21+09:00 Subject: Re: Singleton class, metaclass, eigenclass: what do they mean? On Sat, Dec 4, 2010 at 4:37 AM, Tony Arcieri wrote: > Is there some overall, grand unifying pattern I'm missing then? Because when > I look at Ruby method dispatch it seems a bit like an ad hoc mess If I understand correctly (and I would welcome corrections), the pattern for method lookup is: Looking up "instance methods" : * for an object that is not a class (object.class != Class) * if there is an object.singleton_class * search in the (instance) methods of this object.singleton_class else * search in the (instance) methods of the object.class * then recursively follow the super pointer upwards from there * for the object.singleton_class, the super pointer will point to object.class * for "normal" classes, the super pointer will point to the class from which this "normal" class inherits or optionally to an ICLASS that is a proxy for an included module * until we reach BasicObject Looking up "class methods": * for an object that is a class (object.class == Class) * there is always an object.singleton_class * search in the (instance) methods of this object.singleton_class * then recursively follow the super pointer upwards from there * for the object.singleton_class and higher-up singleton classes, the super pointer will point to object.superclass.singletonclass, thus forming a parallel super-chain of singleton classes (until # is reached, then we jump to Class) * for "normal" classes, the super pointer will point to the class from which this "normal" class inherits or optionally to an ICLASS that is a proxy for an included module * until we reach BasicObject * Note 1: If I understand correctly, for an object that is not a class, the singleton_class is not prepared a priori, but is generated at the time when it is called. * Note 2: the ruby 'superclass' method does not always show the immediate thing pointed to by "super". In Ruby 1.9.2, I believe it shows the next thing in the super-chain that is a Class, but in Ruby 1.8.7 superclass on a singleton class shows Class, while there are still intermediate singleton classes, e.g. #. ICLASS's for modules can be in the super-chain as well, but are also not shown by the superclass function (but these can be discovered with self.included_modules - self.superclass.included_modules). References: * "Advanced Rails" (Brad Ediger), O'Reilly * http://www.klankboomklang.com/2007/10/05/the-metaclass/ (has a nice graphic of the parallel super-chain formed by singleton classes) Corrections welcome, Peter Example for instance d of class D, without a singleton class: ============================================================= $ irb ruby-1.9.2-head > class D < Object; end => nil ruby-1.9.2-head > d= D.new => # ruby-1.9.2-head > d.class => D ## this shows that d is _not_ a class ruby-1.9.2-head > d.singleton_class => #> ## is created ad-hoc ruby-1.9.2-head > d.singleton_class.instance_methods(false) => [] ## but has no methods, so search in D ruby-1.9.2-head > D.superclass => Object ruby-1.9.2-head > D.superclass.included_modules - D.superclass.superclass.included_modules => [Kernel] # Object has the Kernel module included, so that will be searched also ruby-1.9.2-head > D.superclass.superclass => BasicObject ruby-1.9.2-head > D.superclass.superclass.superclass => nil ruby-1.9.2-head > D.ancestors => [D, Object, Kernel, BasicObject] Example for instance e of class E, with a singleton class: ========================================================== ruby-1.9.2-head > class E < Object; end => nil ruby-1.9.2-head > e = E.new => # ruby-1.9.2-head > e2 = E.new => # ruby-1.9.2-head > class << e # opening the singleton class of _object_ e ruby-1.9.2-head ?> def my_singleton_method ruby-1.9.2-head ?> "my_singleton_method, defined in e.singleton_class" ruby-1.9.2-head ?> end ruby-1.9.2-head ?> end => nil ruby-1.9.2-head > e.my_singleton_method => "my_singleton_method, defined in e.singleton_class" ruby-1.9.2-head > e2.my_singleton_method ## no luck, the singleton method is only for e NoMethodError: undefined method `my_singleton_method' for # from (irb):25 from /home/peterv/.rvm/rubies/ruby-1.9.2-head/bin/irb:16:in `
' ruby-1.9.2-head > e.class => E ruby-1.9.2-head > e.singleton_class => #> ruby-1.9.2-head > e.singleton_class.instance_methods(false) => [:my_singleton_method] ruby-1.9.2-head > E.superclass => Object ruby-1.9.2-head > E.superclass.included_modules - D.superclass.superclass.included_modules => [Kernel] ruby-1.9.2-head > E.superclass.superclass => BasicObject ruby-1.9.2-head > E.superclass.superclass.superclass => nil ruby-1.9.2-head > E.ancestors => [E, Object, Kernel, BasicObject] Example with classes (Object, A, B, C) with singleton classes: ============================================================== First this class definition code: class Object class << Object def my_class_method_0 "my_class_method_0, defined in Object.singleton_class" end def my_class_method_1 "my_class_method_1, defined in Object.singleton_class" end def my_class_method_2 "my_class_method_2, defined in Object.singleton_class" end end end class A < Object class << A def my_class_method_0 "my_class_method_0, defined in A.singleton_class" end def my_class_method_1 "my_class_method_1, defined in A.singleton_class" end # NOT defined my_class_method_2 end def my_instance_method_in_A "instance method, defined in A" end end class B < A class << B def my_class_method_0 "my_class_method_0, defined in B.singleton_class" end # NOT defined my_class_method_1 # NOT defined my_class_method_2 end end class C < B # singleton class was not opened end Results in: ruby-1.9.2-head > B.class => Class ## this shows that B is a class ruby-1.9.2-head > B.my_class_method_0 ## in B.singleton_class => "my_class_method_0, defined in B.singleton_class" ruby-1.9.2-head > B.my_class_method_1 => "my_class_method_1, defined in A.singleton_class" ## in B.singleton_class.superclass == A.singleton_class ruby-1.9.2-head > B.my_class_method_2 => "my_class_method_2, defined in Object.singleton_class" ## in B.singleton_class.superclass.superclass == Object.singleton_class ruby-1.9.2-head > C.my_class_method_0 ## in C.singleton_class.superclass => "my_class_method_0, defined in B.singleton_class" ruby-1.9.2-head > A.my_class_method_0 ## in A.singleton_class => "my_class_method_0, defined in A.singleton_class" ruby-1.9.2-head > B.singleton_class.instance_methods(false) => [:my_class_method_0] ruby-1.9.2-head > A.singleton_class.instance_methods(false) => [:my_class_method_0, :my_class_method_1] ruby-1.9.2-head > super_chain = [] ; sc = C.singleton_class => # ruby-1.9.2-head > while sc ruby-1.9.2-head ?> super_chain << sc ruby-1.9.2-head ?> sc = sc.superclass ruby-1.9.2-head ?> end => nil ruby-1.9.2-head > super_chain => [#, #, #, #, #, Class, Module, Object, BasicObject] Note: this last result does not show the modules (e.g. Kernel) that are also included in the internal super-chain but are not shown by the ruby superclass method