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.
Class method frontend that we defined earlier is nothing but an instance method defined in the metaclass for the object Developer ! A metaclass is essentially a class that Ruby creates and inserts into the inheritance hierarchy to hold class methods, thus not interfering with instances that are created from the class.
Classes may generate instances (objects), and have per-instance state (instance variables). Modules may be mixed in to classes and other modules. The mixed in module's constants and methods blend into that class's own, augmenting the class's functionality. Classes, however, cannot be mixed in to anything.
Metaprogramming is a technique in which code operates on code rather than on data. It can be used to write programs that write code dynamically at run time. MetaProgramming gives Ruby the ability to open and modify classes, create methods on the fly and much more.
[extend] - will add the extended class to the ancestors of the extending classes' singleton class. Other words extend mix the module's functionality into class and makes these methods available to the class itself. [super] - is used for overridden method call by the overriding method.
There are four class objects in play here:
<Class>---class---><Class>
Base #Base
^ ^
| |
| |
super super
| |
| |
<Class> <Class>
Derived---class--->#Derived
Nomenclature:
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:
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>
To clarify and correct what i wrote in the comments regarding the way Ruby hides/exposes eigenclasses, here is the situation:
Ruby 1.8:
(1) The Object#class
method always returns the first real (non eigenclass or iclass) superclass of the actual class of an object.
e.g
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 an eigenclass, it passes over them
and instead returns the first 'real' class it finds in the inheritance hierarchy.
(2) The Class#superclass
method has two cases. If the receiver is not an eigenclass then it simply returns the superclass. However, if the receiver is an eigenclass then this method returns the actual (i.e not necessarily real) class of the receiver.
# case where receiver is a normal class (i.e 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
From above, Class#superclass
behaves as expected in the case of a normal class, but for the eigenclass example it states the superclass of the eigenclass of Module is Class which 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 of Module is actually the eigenclass of Object. I am unsure why Ruby 1.8 has this strange behaviour.
Ruby 1.9:
(1) The Object#class
method behaves identically to the 1.8 version.
(2) The Class#superclass
method no longer has two cases, it now treats eigenclasses the same way it treats normal classes and returns the actual superclass as expected.
e.g
class << Module; superclass; end #=> #<Class:Object>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With