Ruby eigenclass unexpected behaviour

eigenclass, metaprogramming, ruby

Solution

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>

Problem

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?

Original source