What is the relationship between the metaclass of Base and Derived class in Ruby?
metaclass, metaprogramming, ruby
Solution
There are four class objects in play here:
<Class>---class---><Class>
Base #Base
^ ^
| |
| |
super super
| |
| |
<Class> <Class>
Derived---class--->#Derived
Nomenclature:
- <...> is the class of each object.
- The name of the class is on the second line.
- If the name starts with #, it's the eigenclass (aka singleton class).
- super points to a class's superclass
- class points to the class's class.
When you call Derived.class_method, Ruby follows the "right one and then up" rule: First go to the object's class, then follow the superclass chain up, stopping when the method is found:
- The receiver of the "class_method" call is Derived. So follow the chain right to Derived's class object, which is its eigenclass (#Derived).
Derived does not define the method, so Ruby follows the chain up the chain to #Derived's superclass, which is #Base.
- The method is found there, so Ruby dispatches the message to #Base.class_method
You don't think I knew all this stuff off the top of my head, did you? Here's where my brain got all this meta juju: Metaprogramming Ruby.
Part 2. How to make an "eigenclass" (aka "singleton class") come out of hiding
class Object
def eigenclass
class << self
self
end
end
end
This method will return the eigenclass of any object. Now, what about classes? Those are objects, too.
p Derived.eigenclass # => #<Class:Derived>
p Derived.eigenclass.superclass # => #<Class:Base>
p Base.eigenclass # => #<Class:Base>
Note: Above is from Ruby1.9. When run under Ruby 1.8, you get a surprise:
p Derived.eigenclass.superclass # => #<Class:Class>
Problem
In Ruby, we could use `super` within singleton method to call the corresponding super class's singleton method, like the following code shows. ``` class Base def self.class_method puts "Base class method" end end class Derived < Base def self.class_method puts "Derived class method" super end end Derived.class_method # Derived class method # Base class method ``` However, I don't seem quite get how that call to `super` within `Derived.class_method` could reach `Base.class_method`. I'd assume that `class_method` is defined on their metaclass, does that mean their metaclass has parent/child relationship? (I can't quite confirm that by experiments) Update: I'm asking this question because I remembered seeing somewhere there's some kind of relationship bettwen base and derived class' metaclass (but I can't find it any more). In addition to know how actually `super` works, I'd also like to confirm whether the two metaclasses are totally separate or not.