I read this article:
Author makes claim that are flat out wrong. She says: "Class gets
"pushed up" the lookup chain and becomes a superclass." That statement
is flat out wrong. A class object does not inherit from class Class.
In fact, if you try it you will get a TypeError. A class object is an
instance of class Class. If a class object does not inherit from
anything, then it implicitly inherits from class Object, which itself
is an instance of class Class. What happens is as follows: First off,
when a class (aka singleton) method is defined on class Dog, an
eigenclass is created. For all intents and purposes, this eigenclass
becomes the class of the Dog object. Class does not get "pushed up"
the lookup chain. It's the superclass that gets pushed up the lookup
chain, which in this example, is Mammal. In other words, it will look
at Dog's eigenclass and if it doesn't find it there, it will then look
at Mammal's eigenclass, and then Object (so its Object that
continuously gets pushed back) and then BasicObject. Here's an example
that shows Class does not get pushed back, because the class object
never even inherits the eigenclass of Class to begin with (the class
object is simply an instance of Class):
Loading development environment (Rails 3.1.2)
1.9.3p0 :001 > class Mammal
1.9.3p0 :002?> def Mammal.mammal_singleton
1.9.3p0 :003?> puts 'mammal singleton'
1.9.3p0 :004?> end
1.9.3p0 :005?> end
1.9.3p0 :006 >
1.9.3p0 :007 > class Dog < Mammal
1.9.3p0 :008?> def Dog.dog_singleton
1.9.3p0 :009?> puts 'dog singleton'
1.9.3p0 :010?> end
1.9.3p0 :011?> end
1.9.3p0 :012 >
1.9.3p0 :013 > class Object
1.9.3p0 :014?> def Object.object_singleton
1.9.3p0 :015?> puts 'object singleton'
1.9.3p0 :016?> end
1.9.3p0 :017?> end
1.9.3p0 :018 >
1.9.3p0 :019 > class Class
1.9.3p0 :020?> def Class.class_singleton
1.9.3p0 :021?> puts 'class singleton'
1.9.3p0 :022?> end
1.9.3p0 :023?> end
1.9.3p0 :024 > Dog.dog_singleton
1.9.3p0 :025 > Dog.mammal_singleton
1.9.3p0 :026 > Dog.object_singleton
1.9.3p0 :027 > Dog.class_singleton
NoMethodError: undefined method `class_singleton' for Dog:Class
#It fails because class Class is not in the eigenclass lookup chain of
Dog class object, since class Class is not a superclass of Dog.
However, by defining an instance method in class Class, then that will
be able to be invoked on Dog, since Dog is an instance of class Class:
1.9.3p0 :028 > class Class
1.9.3p0 :029?> def class_instance
1.9.3p0 :030?> puts 'class instance'
1.9.3p0 :031?> end
1.9.3p0 :032?> end
1.9.3p0 :033 > Dog.class_instance
So the real question is this, which that article obscured. If I invoke
a method on Dog, will it search the Class hierarchy for an associated
instance method first (and continue looking up the lookup algorithm
for instance methods via Module, Object, and BasicObject which class
Class inherits from) or will it search Dog's eigenclass and its
superclasses' eigenclasses (all the way up to the eigenclass of Object
and BasicObject) first? The proof is in the pudding:
1.9.3p0 :044 > class Object
1.9.3p0 :045?> def Object.sing_method
1.9.3p0 :046?> puts 'singleton method'
1.9.3p0 :047?> end
1.9.3p0 :048?> def inst_method
1.9.3p0 :049?> puts 'instance method'
1.9.3p0 :050?> end
1.9.3p0 :051?> end
1.9.3p0 :052 > Dog.sing_method
1.9.3p0 :053 > Dog.inst_method
#as suspected, invocations on Dog lead to both eigenclass methods of
Object and instance methods of Object, since Dog is an instance of
class Class, and class Class inherits from Object via Module, and Dog
at the same time inherits from Object (via inheritance), which is done
implicitly by Ruby. Now which get invoked first, the instance methods
or eigenclass methods?
1.9.3p0 :062 > class Object
1.9.3p0 :063?> def Object.method_lookup
1.9.3p0 :064?> puts 'eigenclass method called first!'
1.9.3p0 :065?> end
1.9.3p0 :066?> def method_lookup
1.9.3p0 :067?> puts 'instance method is called first!'
1.9.3p0 :068?> end
1.9.3p0 :069?> end
1.9.3p0 :070 > Dog.method_lookup
eigenclass method called first!
And there you have it, the method resolution algorithm looks up the
singleton methods prior to the instance methods of a class object.