What is the relationship between the metaclass of the Base class and Derived in Ruby?

In Ruby, we could use super in the singleton method to invoke the corresponding Superton superton method, as shown in the following code.

 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 to understand how this super call inside Derived.class_method can reach Base.class_method . I would suggest that class_method defined in their metaclass, does this mean that their metaclass has parent / child relationships? (I cannot confirm this experimentally)

Update: I ask this question because I remembered that somewhere there is some kind of attachment to the base and the metaclass of the derived class (but I can no longer find it). Besides the fact that I know how super works, I would also like to confirm whether the two metaclasses are completely separated or not.

+6
metaclass ruby metaprogramming
source share
3 answers

There are four class objects here:

 <Class>---class---><Class> Base #Base ^ ^ | | | | super super | | | | <Class> <Class> Derived---class--->#Derived 

Designations:

  • <...> is the class of each object.
  • The class name is on the second line.
  • If the name starts with C #, this is eigenclass (aka singleton class).
  • super points to the superclass class
  • points to a class class.

When you call Derived.class_method, Ruby follows the "right and then up" rule: first go to the object class, and then follow the superclass chain up, stopping when the method is detected:

  • The call receiver of class_method is derived. So, follow the chain directly to the object of the Derived class, which is its eigenclass (#Derived).
  • Derived does not define a method, so Ruby follows a chain of chains on the #Derived superclass, which is #Base.

  • The method is found there, so Ruby sends a message to # Base.class_method

You don’t think I knew all this from my head, do you? Here, where my brain got all this meta-yu: Ruby metaprogramming .

Part 2. How to create an "eigenclass" (otherwise called a "singleton class") come out of hiding

 class Object def eigenclass class << self self end end end 

This method will return eigenclass of any object. Now, what about classes? These are also objects.

 p Derived.eigenclass # => #<Class:Derived> p Derived.eigenclass.superclass # => #<Class:Base> p Base.eigenclass # => #<Class:Base> 

Note: above from Ruby1.9. When starting under Ruby 1.8, you get a surprise:

 p Derived.eigenclass.superclass # => #<Class:Class> 
+11
source share

To clarify and fix what I wrote in the comments regarding how Ruby hides / expands eigenclasses, here is:

Ruby 1.8:

(1) The Object#class method always returns the first real (not eigenclass or iclass) superclass of the corresponding object class. eg,

 o = Object.new class << o; end o.class #=> returns Object, even though the _actual_ class is the eigenclass of o 

In other words, the Object#class method will never return eigenclass, it will go through them and instead return the first β€œreal” class that it finds in the inheritance hierarchy.

(2) The Class#superclass has two cases. If the receiver is not eigenclass, it simply returns a superclass. However, if the receiver is eigenclass, this method returns the actual (not necessarily real) receiver class.

 # case where receiver is a normal class (ie not an eigenclass) Module.superclass #=> Object (behaves as expected) # case where receiver is an eigenclass class << Module; superclass; end #=> returns Class, this is NOT the superclass 

At the top, Class#superclass behaves as expected in the case of a normal class, but for the eigenclass example it is indicated that the superclass of the module eigenclass class is a class that is not true. From this diagram, http://banisterfiend.wordpress.com/2008/10/25/the-secret-life-of-singletons/ we know that the superclass of the Eigenclass class is actually an Object. I'm not sure why Ruby 1.8 has this weird behavior.

Ruby 1.9:

(1) The Object#class method behaves the same with version 1.8.

(2) The Class#superclass no longer has two cases, it now treats eigenclass as it does with normal classes and returns the actual superclass as expected.

eg

 class << Module; superclass; end #=> #<Class:Object> 
+4
source share

This diagram explains the relationship: http://banisterfiend.wordpress.com/2008/11/25/a-complete-ruby-class-diagram/

In addition, here are a few other posts that explain more complex work with eigenclasses: http://www.klankboomklang.com/2007/10/05/the-metaclass/

http://www.klankboomklang.com/2007/09/21/the-singleton-class/

And here is quite complicated, which explains more than you probably would like to know: http://banisterfiend.wordpress.com/2008/10/25/the-secret-life-of-singletons/

+3
source share

All Articles