In Progress
Unit 1, Lesson 21
In Progress

Singleton Class Exec

Ruby’s “singleton classes” are like dark matter: they are everywhere, and they explain why things work the way they do. But they are, for the most part, invisible. Which makes them hard to understand.

In this episode we’re going pull the curtain back on singleton classes. You’ll learn how to see these elusive entities hovering in the background of Ruby’s object model, and relate them to the language features you use every day.

Video transcript & code

In episode #453 we met Cletus, the Dancing Cow.

And we discovered that when we defined the dance method on the single Cow object named cletus, Ruby was actually storing this method definition in a special object-specific class called a "singleton class".

class Cow
  def speak
    "moo"
  end
end

cletus = Cow.new

def cletus.dance
  "tappety tappety tap"
end

cletus.dance
# => "tappety tappety tap"

cletus.singleton_class
# => #<Class:#<Cow:0x0055c2fa1f8160>>

cletus.singleton_class.instance_methods(false)
# => [:dance]

Later on, in episode #454, we discovered that so-called class methods in Ruby are also just another example of singleton methods.

When we define a plural_term class method, , it turns out it's really just another instance method. An instance method defined on the singleton class of the Cow class object.

class Cow
  def self.plural_term
    "herd"
  end

  def speak
    "moo"
  end
end

Cow.singleton_class
# => #<Class:Cow>

Cow.singleton_class.instance_methods(false)
# => [:plural_term]

Now, I've always found singleton classes to be one of the most difficult Ruby concepts to wrap my brain around. And I know a lot of other folks have the same problem.

And I think that maybe the biggest reason for this difficulty is simply that singleton classes are invisible most of the time. Unless we specifically go looking for them, as we have here.

Let's change that. Let's get rid of our our current definition of the dance method.

Now let's rewrite it. This time, we'll start by asking for the singleton_class corresponding to the cletus object.

Then we tell that class, we want to execute some code inside its context, using class_exec.

And inside the class_exec block, we define an ordinary instance method called dance.

The outcome of this definition is exactly the same as before.

We can tell cletus to dance, and he does.

And we can see that this dance method is in fact defined in the object's singleton class.

class Cow
  def self.plural_term
    "herd"
  end

  def speak
    "moo"
  end
end

cletus = Cow.new

cletus.singleton_class.class_exec do
  def dance
    "tappety tappety tap"
  end
end

cletus.dance
# => "tappety tappety tap"

cletus.singleton_class.instance_methods(false)
# => [:dance]

But this time, this should come as less of a surprise. Partly because we've already learned about it. But also, because this time we explicitly defined the method inside the singleton class.

Now, Ruby hasn't always had a method for getting at the singleton_class. In fact, it hasn't always had a class_exec method either.

But even before either of these methods existed, Ruby had a way of explicitly modifying an object's singleton class. And it looked like this.

class << cletus

This special variation on class definition syntax opens up an objects singleton class and allows us to add or modify the methods defined there. In this case, we're adding a sing method.

The outcome is the same as our class_exec version. Cletus is now a singing and dancing cow. And we can see both methods are stored in the singleton class.

class Cow
  def self.plural_term
    "herd"
  end

  def speak
    "moo"
  end
end

cletus = Cow.new

cletus.singleton_class.class_exec do
  def dance
    "tappety tappety tap"
  end
end

class << cletus
  def sing
    "ga ga moo-la-la!"
  end
end

cletus.dance
# => "tappety tappety tap"

cletus.sing
# => "ga ga moo-la-la!"

cletus.singleton_class.instance_methods(false)
# => [:dance, :sing]

So next time you see per-object methods defined using the "def object dot method" syntax, you can realize exactly what this really is: a shorthand for defining instance methods in a singleton class.

class Cow
  def self.plural_term
    "herd"
  end

  def speak
    "moo"
  end
end

cletus = Cow.new

def cletus.dance
  "tappety tappety tap"
end

def cletus.sing
  "ga ga moo-la-la!"
end

And you can even rewrite it in your head to one of these more explicit versions.

class Cow
  def self.plural_term
    "herd"
  end

  def speak
    "moo"
  end
end

cletus = Cow.new

cletus.singleton_class.class_exec do
  def dance
    "tappety tappety tap"
  end
end

class << cletus
  def sing
    "ga ga moo-la-la!"
  end
end

And the same goes for class object singleton methods, otherwise known as "class methods".

class Cow
  def self.plural_term
    "herd"
  end

  def speak
    "moo"
  end
end

You can mentally rewrite this to a version that explicitly acknowledges the existence of the singleton class.

class Cow
  singleton_class.class_exec do
    def plural_term
      "herd"
    end
  end

  def speak
    "moo"
  end
end

Once you start seeing singleton classes this way, you'll realize that they are everywhere. And that they aren't as mysterious as they first appeared. Happy hacking!

Responses