First, let's add a method to retrieve eigenclass "copied from this blog post"
class Object
def eigenclass
class << self
self
end
end
end
Then create a simple class
class A
end
puts A.new.eigenclass.superclass # => A
puts Class.new.eigenclass.superclass # => #<Class:Object>
I was expecting the second puts to output Class
Any clue why this happened?
By puts A.new.eigenclass.superclass
, you are effectively calling #eigenclass
on the instance of class A. I will begin with backstory to explain how eigenclass actually works, and will then proceed to tell what is happening in your code.
BackStory:
EigenClass is a hidden class which contains the singleton methods available for that specific object only.
So for obj = Foo.new
, the class hierarchy actually looks like:
obj --eigenclass--> #> --(superclass)--> A
instead of:
obj --(class)--> A
A hidden class can be produced after you hijacked the self with #eigenclass
.
Now, in Ruby, Class is an object. This also means that #eigenclass
should show the the hidden eigenclass of A
too (where A's sigleton methods are kept).
A --(eigenclass)--> # --(superclass)--> #
Now the reason why it shows # instead of A
is because Ruby organizes the classes, superclasses and eigenclasses in a very beautiful pattern. This can be shown with example instead of quoting it in confusing words:
A.superclass #=> Object
A.eigenclass #=> #<Class: A>
A.eigenclass.superclass #=> #<Class: Object> => Eigenclass of Object
A.eigenclass.superclass == Object.eigenclass #=> true
The superclass of an eigenclass of a class is the eigenclass of the superclass of the original class.
Now, coming to your case: Class.new.eigenclass.superclass
, this is self-explanatory now. Class.new
corresponds to a new anonymous class, say B
, and you are effectively calling eigenclass.superclass
on it. Since the superclass of B
is Object, the superclass of eigenclass of B is the eigenclass of superclass of B
.
Tried my best to explain with examples. Please feel free to clarify it further in comments below; will update the answer accordingly. Complementary(from Pragmatic MR): .
In the figure shown above, D
inherits from C
. So D.eigenclass.superclass
is the eigneclass of (superclass of D)[which is C]. Now C's superclass is Object.. and so is the same logic.
Regards
From that blogpost, you can construct a similar diagram:
+------------------+ +-------------------+
| Object |- eigenclass ->| Object eigenclass |
+------------------+ +-------------------+
^ ^
| superclass superclass |
+------------------+ +-------------------+
| A |- eigenclass ->| A eigenclass |
+------------------+ +-------------------+
^
| superclass
+-------+ +------------------+
| A.new |- eigenclass ->| A.new.eigenclass |
+-------+ +------------------+
Trying to find the superclass of the eigenclass of an instance of A shows that it points to the A
class.
A.new.eigenclass.superclass # => A
Class.new
returns an instance of a Class object, i.e. a new class. It is a class, just like the A
class.
Class.new.class # => Class
A.class # => Class
A's superclass and Class.new's superclass are both implicitly Object
.
Class.new.superclass # => Object
A.superclass # => Object
Because A's superclass is Object
, A's eigenclass's superclass is Object's eigenclass.
Object.eigenclass # => #<Class:Object>
A.eigenclass.superclass # => #<Class:Object>
A.eigenclass.superclass == Object.eigenclass # => true
Similarly, finding the superclass of the eigenclass of Class.new
yields Object's eigenclass
Class.new.eigenclass.superclass # => #<Class:Object>
The difference between Class.new
and A.new
is that Class.new
is itself a class and so can construct new objects, while A.new
cannot.
Class.new.new # => #<#<Class:0x007f86b50d8f70>:0x007f86b50d8f20>
A.new.new # => NoMethodError: undefined method `new' for #<A:0x007f86b50cbf50>
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