rubyclasseigenclass

What is a singleton class in Ruby?


I m having trouble understanding the concept of eigenclass or singleton class in ruby. I read a lot that the eigenclass is a class's class. That doesn't make sense to me as for me a class's class is actually Class as all classes are actually instances of the class Class.

Another thing I don't quite get is the following statement: a class method is actually an instance method of the class eigenclass. The eigenclass is accessible this way :

YourClass = Class.new
class << YourClass
  def class_method
  end
end

But if the eigenclass is indeed the YourClass class (that is Class), shouldn't the preceding piece of code open the class Class and add to it the instance method class_method making it accessible to all of its future instances (that is any regular class defined in the future)?

I actually kind of feel that the singleton class is not the same as Class. When you do :

class MyClass
end

MyClass.singleton_class

you get #<Class:MyClass> which is different from the output of MyClass.class => Class

What is that #<Class:MyClass> output ? This has nothing to do with namespace as otherwise there would be two: Class::MyClass...

I'm Looking for a simple and unambiguous explanation of the eigenclass concept in order to clarify my ideas.


Solution

  • Singleton classes hold methods that are specific to a single object.

    For generic objects, it's a nice-to-have feature. But for classes, it's crucial. Let's start with the objects:

    Singleton classes for objects

    Instance methods are usually defined in classes. All instances of the same class share the same instance methods. The singleton class sits between the object and its class. It allows each instance to have its own set of methods, independent of the other instances.

    If we have two classes, Foo and Bar with 2 instances each a, b and c, d:

    class Foo ; end
    class Bar ; end
    
    a = Foo.new #=> #<Foo:0x00007fc280963008>
    b = Foo.new #=> #<Foo:0x00007f8319016b18>
    c = Bar.new #=> #<Bar:0x00007fa66c8d7290>
    d = Bar.new #=> #<Bar:0x00007f94d5106ac8>
    

    You would have this class structure: (simplified, excluding modules)

    object          singleton class              class    superclass   ...
    
      a ── #<Class:#<Foo:0x00007fc280963008>> ─┐
                                               ├─ Foo ─┐
      b ── #<Class:#<Foo:0x00007f8319016b18>> ─┘       │
                                                       ├─ Object ── BasicObject
      c ── #<Class:#<Bar:0x00007fa66c8d7290>> ─┐       │
                                               ├─ Bar ─┘
      d ── #<Class:#<Bar:0x00007f94d5106ac8>> ─┘
    

    Ruby creates those singleton classes lazily, for example when calling singleton_class.

    So when defining a method a.hello, it is not stored in a's class Foo, but in a's singleton class:

    def a.hello
      'hello from a'
    end
    
    a.method(:hello).owner
    #=> #<Class:#<Foo:0x00007fc280963008>>  <-- a's singleton class
    

    Because of that, b doesn't see that method, even though both are Foo instances:

    b.hello #=> NoMethodError: undefined method `hello'
    

    And we can even define a method with the same name for b without interfering with a:

    def b.hello
      'hello from b'
    end
    
    b.method(:hello).owner
    #=> #<Class:#<Foo:0x00007f8319016b18>>  <-- b's singleton class
    
    a.hello #=> "hello from a"
    b.hello #=> "hello from b"
    

    We could also define a generic hello in Foo and override it on a per instance level: (you usually don't do that, but it's possible)

    class Foo
      def hello
        'hello'
      end
    end
    
    def a.hello
      "#{super} from a"
    end
    
    def b.hello
      "b says #{super.upcase}!"
    end
    
    a.hello #=> "hello from a"
    b.hello #=> "b says HELLO!"
    
    c = Foo.new
    c.hello #=> "hello"
    

    Singleton classes for classes

    The above is especially important for classes. Each class is an instance of Class:

    Foo.class #=> Class
    

    Let's say we wanted to have a method Foo.hello, where would we define it?

    Instance methods are usually defined in the instance's class, so we could define it in Foo's class:

    class Class
      def hello
        'Hello from Foo'
      end
    end
    
    Foo.hello
    #=> "Hello from Foo"
    

    But that would make the method available to all instances of Class:

    Bar.hello
    #=> "Hello from Foo"
    
    String.hello
    #=> "Hello from Foo"
    

    It would be better to have a place that's exclusive to the Foo instance. And that place is Foo's singleton class:

    def Foo.hello
      'Hello from Foo'
    end
    

    or

    class Foo
      def self.hello       # <-- self is Foo, so this is just "def Foo.hello"
        'hello from Foo'
      end
    end
    

    Just like a.hello above, this method is only available to Foo:

    Foo.hello #=> "hello from Foo"
    Bar.hello #=> NoMethodError
    

    We call these methods class methods, but they are really just instance methods of the singleton class:

    Foo.method(:hello).owner
    #=> #<Class:Foo>   <-- Foo's singleton class
    
    Foo.method(:hello).unbind == Foo.singleton_class.instance_method(:hello)
    #=> true
    

    And if you compare the singleton methods for classes with those for objects, you'll see that they are identical. That's because in Ruby, classes are objects too, and all objects work alike.