rubymetaprogrammingeigenclass

Ruby eigenclass unexpected behaviour


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?


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>