What is a singleton class in Ruby?

2.5k views Asked by At

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.

3

There are 3 answers

0
Stefan On BEST ANSWER

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.

10
BobRodes On

I think you're getting a bit off track by confusing the idea of the eigenclass with the idea of a Ruby class instance. They aren't exactly the same; it's more correct to say that Ruby implements class definitions internally as two objects.

This is easily enough demonstrated:

$ irb
> ObjectSpace.count_objects[:T_CLASS]
 => 1285 
> Foo = Class.new { def instance_method; end }
 => Foo 
> ObjectSpace.count_objects[:T_CLASS]
 => 1287

Internally, every object has a klass pointer, which on the surface points to the class the object is an instance of. However, every object (except certain primitives such as Integer, Float and Symbol) also has an eigenclass instance, and this is what the klass pointer actually points to. In the case of classes, then, the klass pointer doesn't actually point to the Class class, but to the singleton object that's part of the class definition, and that contains the method table that holds the class methods.

As the link that anothermh provides explains, the "ordinary" class object's method table contains all the class's instance methods, while the eigenclass object's method table contains all of the class's class methods. This is the mechanism that prevents all of the class's class methods from being accessible to any instance of the Class class.

Now, the eigenclass (eigen is German for "own" in the sense of "my own") is the class of the class, which is why it's also called a metaclass. (Have a look at the source code for Class::new and you will see a call to rb_make_metaclass.)

This is why a call to MyClass.singleton_class returns #Class:MyClass rather than Class as a call to MyClass.class does. This syntax is analogous to p Foo.new returning something like #<Foo:0x00007f9c0d190400>, which is the class and the pointer to the instance. With #Class:MyClass, MyClass is the pointer to the instance. So, this describes a reference to MyClass's metaclass, or the class of MyClass. This is not to be confused with what class MyClass is an instance of, which, of course, is Class.

In case you're curious, the klass pointer in the eigenclass instance actually points to itself. This is demonstrated by the fact that MyClass.singleton_class.singleton_class returns #Class:#Class:MyClass.

For a more comprehensive overview, see Demystifying Ruby Singleton Classes. For a look at what's going on in the source code, see The Ruby Hacking Guide: Chapter 4. Finally, Ruby Under a Microscope is an excellent resource for a comprehensive deep dive into Ruby internals.

[Edited to incorporate some of the discussion in comments]

0
Aetherus On

Eigenclass is no longer a name used in the Ruby world because Ruby officially introduced a method Object#singleton_class in I don't know which version (sorry).

Every object in Ruby, being a "normal" object or a class, or even a singleton class, has its own singleton class.

A singleton class is a class.

Object.new.singleton_class.is_a?(Class)  #=> true

A singleton class has and only has one instance, and it's the object you call singleton_class on. e.g. the only instance of foo.singleton_class is foo.

Ruby allows you to add methods to individual objects.

a = Object.new
b = Object.new

def a.foo
  'foo'
end

a.foo  #=> "foo"
b.foo  #=> raises NoMethodError 

But all instance methods should be defined in a class, so in which class is a.foo defined? The answer is a.singleton_class. Because a.singleton_class only has one instance that is a, the instance method foo can only be called on a, not on b, though they are of the same type.

As for the class's singleton classes, their purpose is to store the "normal classes'" class methods, or if you twist your brain a little, the instance methods that are bound to the individual class instances.

Don't you feel Ruby's object model consistent and beautiful?