Noel Rappin Writes Here

Better Know A Ruby Thing: Singleton Classes

Posted on January 20, 2025


It is time to Better Know what is perhaps the Ruby-iest of Ruby things, a feature that didn’t even have an official name for several years, despite being critical to Ruby’s Object-Oriented semantics. (It only just now occurs to me that there was no official name in English, I wonder what the Japanese name for it was…).

Yes, it’s the singleton class.

Which isn’t really a singleton. Or really a class. It is the “grape-nuts cereal” of Ruby features.

The singleton class has been known by other unofficial names over the years. It’s been called a “metaclass” although technically it is not a metaclass, it has been called an “eigenclass”, a name I always favored because nobody knows what an eigenclass is, so whose to say whether it is one.

I went down a small rabbit hole on “eigenclass”. As far as I can tell, the term “eigenclass” is unique to Ruby, but I didn’t look that hard, maybe Matz picked it up from some obscure 60s language. I think it’s analogous to the math term “eigenvalue”, which Wikipedia says is a term in linear algebra. I may have known what that meant at some point, but I sure don’t know it any more. “Eigen” is a German word that is a cognate with the English word “own” (thanks Wikipedia) but not the sense of “own” that means “has possession of” – the sense that means “very own”, or “is characteristic of”, as in “my very own way of thinking” or “Chicago’s very own hot dog”. So an “eigenclass” is somehow a characteristic class.

Anyway, the lack of naming convention was super confusing, especially if you were trying to teach Ruby. Ruby 2.1 introduced a accessor method named singleton_method, and I think that was what settled the naming convention, to a general sigh of relief from the “people who write about Ruby” community.

Singleton classes are often taught as just an odd bit of syntax. Well, as three odd bits of syntax:

  • Using def self.foo to create a “class method”
  • Being able to arbitrarily use any object in a method definition, as in def x.foo
  • Direct access to the singleton class via self << class do ... end.

But these are all tightly related and are more than merely an odd bit of syntax, they are a solution to a particular language design problem.

Specifically, the problem of how to have methods attach to a class in a pure Object-Oriented language.

The Problem of Class Methods

Because of the way Ruby classes work, it’s a challenge to attach a method to a specific class and not all classes or all instances of a class.

In a pure Object-Oriented language like Ruby or Smalltalk, everything is an object. Classes themselves are objects – a class is an instance of the class Class (writing about this stuff leads to tongue twisters pretty quickly).

There’s a little bit of a logical tangle here: classes are “merely” objects, yes, but classes are also a special kind of object. Within Ruby class objects are unique in that they can create other objects – the instances of that class.

A Ruby class is created by the keyword class followed by an object name (with an optional superclass), and then inside the class definition, you typically define a bunch of methods. The first fun fact here is that the class name, as we discussed in a previous Better Know, is a constant, and the value of that constant is the instance of the class Class created by Ruby when the class is defined. The methods defined in the body of the class become instance methods of the class.

To oversimplify somewhat, when Ruby interprets a def statement, Ruby takes the resulting method and adds it to an instance variable of the surrounding class Class which contains a table of all instance methods. Ruby then uses that table when looking up methods at run time when they are called.

This is all well and good, or at least it’s reasonably transparent to a Ruby developer, but it’s missing a common object-oriented feature, the “class method” (or in some languages, “static method”).

Instance methods are called with regular instances as receivers. But it’s also useful to have methods that are attached to the class itself. These contain behavior for the class itself, typically things like alternate constructors, or data shared by all instances, and so on.

What you want is a way to be able to define a method called, say, User.from_data, and for that method to only belong to the User class.

I’m over explaining here, perhaps, but I want to get across just how odd the method call User.from_data is in Ruby. In this case from_data is not an instance method of Class (the way that new is an instance method of Class)

The from_data method needs to specifically attach to the exact instance representing the class User and only to that instance. This is different from normal instance method behavior, a normal instance method attaches to all instances. This is the kind of thing that makes perfect sense when you read the line of code calling User.from_data, and only gets complicated when you have to worry about how to implement that behavior.

So, you need a method that only attaches to a single object, rather than to all instances of a class. This is a weird thing – if you aren’t talking about instances of the class Class, it would sound kind of absurd.

Like, abs is a method of Integer, and it applies to all integers. It would be odd if you only wanted abs to be callable for, like, the number 37. Lots of Ruby tutorials go out of their way to explain how to attach methods to individual instances, but in practice 99.99% of the time the use case is for individual instances of Class. Which is to say, for class methods.

What it comes down to is that the User instance of class is expected to behave differently from an Address instance of class in a way that is not true of, say the String "x" and the String "y", and so there’s more of a need for unique methods attached to each individual class.

So, to make class methods work, you need some way to attach a method to an individual instance – not an “instance method” in the way that every instance of a given class has the ability to call that method, but a “method of an instance” in the sense that only one instance knows about and can call that method.

Let’s look at how other languages address this problem.

Python and Smalltalk

In Python, new classes are (by default) instances of type. Python objects are essentially just key/value stores where the values can be either regular values or callable objects (methods). You can attach a callable object to any instance variable, but there is language support (via the @classmethod decorator) for attaching a callable object specifically to a type, making it relatively easy to define class methods, and possible, but more challenging, to attach methods to arbitrary instances. A side effect of this setup is that Python, unlike Ruby, has a single namespace combining instance values and method names, and also unlike Ruby, makes a distinction between “accessing a value”, which you do without parentheses, and “calling a method” which has parentheses.

In Smalltalk… well, Smalltalk is confusing and I’m not 100% sure I’ve got this. Here’s a stab. A new class in Smalltalk is an instance of a “metaclass”, and each class gets its very own metaclass. So a Smalltalk class called User is actually the only instance of a metaclass called User class. The metaclass is itself an instance of a class called Metaclass.

When you create a new class in Smalltalk, you just create the class, the metaclass is created for you by the system. What we’ve been calling “class methods” are actually instance methods of the metaclass. In syntax, you call using the class as the receiver (as in User fromData: data), and the system internally directs the call to the method of the metaclass.

In Smalltal, you interact with your code through an code browser that is part of the system. The Smalltalk code browser mashes the class and metaclass together in the interface, so you see “class methods” as a kind of method you can create on the class, but behind the scenes the method is attached to the metaclass, and the Smalltalk system makes sure that uses of class methods are looked up in the associated metaclass.

Where this gets weird – if you didn’t think it was already weird – is that Metaclass, being a class, has its own metaclass, which, circularly, is an instance of Metaclass. Don’t stare at that sentence too long, you’ll hurt your eyes.

The upshot is that arbitrary Smalltalk instances can’t have methods attached to them, but individual classes effectively can have methods attached to them through the expedient of a metaclass of which that class is the only instance, and the development environment blends the class and metaclass together seamlessly enough that you don’t normally need to worry about the existence of the metaclass. It all just works.

Ruby Singleton Classes

Ruby has elements of both the Python and Smalltalk solutions – like Python, Ruby allows methods to be added to any arbitrary instance, not just classes. Like Smalltalk, it does this with the addition of an additional class-like object. Unlike Smalltalk, the Ruby class-like object is not a parent of the class, it’s an attribute of the class.

In Ruby, every object that is instantiated is represented internally by basically three things:

  • A table of instance values
  • A pointer to the class of the object, used for method lookup
  • A pointer to a unique class for that instance, called the “singleton class” of the object, also used for method lookup

The first two items are pretty consistent among Object-Oriented languages, the third one is the way in which Ruby manages to store methods on an individual class.

The “singleton class” is an actual Ruby class – meaning that it is an instance of the class Class. The singleton class is created automatically by Ruby and it is unique to that instance – two different instances of the same class will get different singleton classes, which you can see with code like this:

irb(main):001> x = "Fred"
irb(main):002> y = "Barney"
irb(main):003> x.singleton_class
=> #<Class:#<String:0x000000011eacefd0>\>
irb(main):004> y.singleton_class
=> #<Class:#<String:0x000000011e4ea6c8>\>

I think – but I’m not 100% sure – that the singleton class is eagerly created when new class objects are created, but for other objects is only created lazily when requested. As a result, the actual performance overhead is minimal, since 99.99% of objects won’t ever create a singleton class.

Since the singleton class is a class, you can define methods inside it. And the important part of why singleton classes work is that the singleton class is the first place Ruby looks for a method. In other worlds, when you call a method like user.first_name, Ruby will look in the singleton class for the specific user instance first, and will only look for an instance method of the class if there is no matching method in the singleton class.

If the receiver of the method is a class name, as in User.create_from_data, the first place Ruby looks is the singleton class of the instance – in this case the instance is User. This is a class method, that’s how class methods work.

The fact that User is a class is incidental here – Ruby always looks at the singleton class, it’s just that there’s very little incentive to use a singleton class unless the receiver is a class, there’s hardly any other case where calling a method on an specific instance is valuable.

Ruby’s syntax

There are at least three ways to define a method in a Ruby singleton class. Two of these are syntactic shortcuts that tell Ruby that defined methods should be placed in a singleton class.

The one you are most likely to see is a variation on the normal def syntax to create a method. The method name is prefixed with an object reference, just as though it was a method call. This is most often seen as a way to define class methods:

class User
  def self.create_from_data

  end
end

The self. before the method name tells the Ruby parser that the method doesn’t go where it would otherwise go (in the containing class) instead the method is stored in the singleton class for self, which, given that self is referenced inside a class and outside a method, means that self is the User class. Again, this is a class method. Older versions of Ruby didn’t allow self there, so you used to see the class name directly, as in def User.create_from_data.

But this mechanism is not limited to classes – this is the kind of contrived example I was alluding to earlier.

x = "Fred"
y = "Barney"

def x.shout
  "Hey #{self.upcase}"
end

x.shout # => "Hey FRED"
y.shout # => No Method Error

In this case, we’re using the same thing to tell Ruby to place the shout method in the singleton class for x. There’s nothing special about x, it’s just an ordinary instance, but we can still define a method that applies to x and only x.

The second syntax is a little less common:

class User
  class << self
    def create_from_data

    end
  end
end

The syntax here is class << OBJECT, where “OBJECT” can be any Ruby object. The semantics is that until you hit an end keyword, all method definitions inside the class << statement are sent to the singleton class of the object on the right of the <<, in this case self which references the User class.

Again, there’s nothing special about self here, and you can use class << with any arbitrary object.

x = "Fred"
y = "Barney"

class << x
  def shout
    "Hey #{self.upcase}"
  end
end

x.shout

The typical use case for class << is having a lot of class methods and you want to define them together without repeating def self. on each one.

I’m not sure what temperature take this is, but I prefer def self.foo to class << self for much the same reason that I prefer private def foo – it places important information about the method call at the point of the method declaration, not at some arbitrary point above the method declaration.

You can also get at the singleton class with the method singleton_class, so you could do something like this:

x = "Fred"
x_singleton = x.singleton_class
x_singleton.define_method(:shout) do
  "HEY #{self}"
end

Ruby has a shortcut here, the method define_singleton_method.

x = "Fred"
x.define_singleton_method(:shout) do
  "HEY #{self}"
end

Honestly, I think I like x.define_singleton_method(:foo) more than def x.foo for non-class objects on the grounds that it’s more explicit, but that’s a pretty weak opinion, using either should be quite rare.

The eternal question… Why is Ruby like this?

I’ll be frank and admit I’m not really sure why the Smalltalk solution wasn’t used. In practice, Ruby’s behavior is very similar to Smalltalk, it’s hard to imagine another scenario where you’d reasonably want to pin an method on a particular instance, it seems like you could make metaclasses just be a part of how classes work – Ruby already does special work when classes are created.

My guess is that it’s at least partially a workaround for the fact that Smalltalk has a built-in IDE and Ruby doesn’t. There’s no special syntax to create regular classes in Smalltalk, you just send a message to the system in the code browser saying that a new class should be created.

In Smalltalk, you don’t need bonus syntax to denote a class method because the way Smalltalk works, you just enter them in the part of the IDE that is marked “class methods” and the system puts them in the right place. Most of the time you don’t even have to know that the metaclass exists.

But Ruby’s a scripting language and doesn’t have a built-in IDE, so there needs to be some kind of syntax to denote a “class method”. From that point, using dot syntax makes sense. Why that syntax is def self.foo and not, say, self.def foo, I’m not sure. I assume that parsing self.def would be complicated, but I don’t really know.

And that’s the singleton class, a Very Ruby Way to get an important OO feature and still keep the object system consistent.



Comments

comments powered by Disqus



Copyright 2025 Noel Rappin

All opinions and thoughts expressed or shared in this article or post are my own and are independent of and should not be attributed to my current employer, Chime Financial, Inc., or its subsidiaries.