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.

Original source