By

Assigning methods to specific objects and not their classes in Ruby

On most days when you use Ruby, you write a class and bestow upon it some methods, then instantiate it and use its methods:

class Crossfield < FederationShip
  def goto(location)
    puts "Warping to #{location}"
  end
end

crossfield = Crossfield.new
crossfield.goto(:starbase_9)
# Warping to starbase_9

Everything is going as it should be, until one day, you decide an instance is going to be special. It will walk differently.

discovery = Crossfield.new

def discovery.goto(location)
  puts "Spore Jump to #{location}"
end

Wait you can do that? What happens if I call goto now?

crossfield.goto(:starbase_9)
# Warping to starbase_9

discovery.goto(:starbase_9)
# Spore Jump to starbase_9

What just happened there?

On the surface it seems like you have just modified an instance to return a different method. But wait, aren’t methods only defined on classes? This isn’t JavaScript where classes and instances are just objects that quack right?

If you were thinking that, you are right. Methods in Ruby can only be defined on classes, and they can only be called when bound to an instance. What just happened was that we defined a method on a Singleton Class

What is a Singleton Class?

In Ruby, every object comes with a Singleton Class. Not to be confused with Singletons which refer to the Singleton Pattern, Singleton Classes are special classes that accompany every object in Ruby.

# Extracting the Singleton Class
discovery.singleton_class
 => #<Class:#<Crossfield:0x00007f92...>>

Singleton Classes inherit from the class that an object is an instance of, so any methods defined on it are available on the instance, as with normal class inheritance rules:

discovery.singleton_class.ancestors
 => [
  #<Class:#<Crossfield:0x00007f92...>>, 
  Crossfield,
  FederationShip, 
  Object, 
  Kernel, 
  BasicObject
 ]

Singleton Classes however are specific to a particular instance, so modifying such a Singleton Class only modifies that instance’s Singleton Class.

# Syntax to modify an instance's Singleton Class
class << discovery
  def grow_spores
    puts 'Growing Spores'
  end
end

discovery.grow_spores
# Growing Spores

Looks familiar? That is because it is basically similar to defining a Class Method.

Class methods

You might now be thinking, so wait a minute, if we defined instance methods on a class, what are class methods? Well, in Ruby everything is an Object, so Classes are Objects too. They are instances of the Class class.

That means that every class has their own Singleton Class too.

The class Class is also an Object, and therefore also has a singleton class too.

This is how you would have seen people define class methods:

# How we normally define class methods:
class FederationShip
  def self.prefix
    'NCC'
  end
end

FederationShip.prefix
=> "NCC"

This is another way you would have seen a class method being defined:

class FederationShip
  class << self
    def prefix
      'NCC'
    end
  end
end

You can also use it in this way:

class << FederationShip
  def prefix
    'NCC'
  end
end

Or even just:

def FederationShip.prefix
  'NCC'
end

Essentially, the class << FederationShip syntax is syntactically equivalent to:

FederationShip.singleton_class.class_eval do
  # inside
end

In fact, you can retrieve the Singleton Class in that manner:

# This was the way you had to extract the Singleton Class before the introduction of the singleton_class method.
class << FederationShip
  self
end
=> #<Class:FederationShip>

A Singleton Class of a class, unlike the Singleton Class of an object, does not have parents that are related to the class itself, because the class isn’t an instance of itself:

Crossfield.singleton_class.ancestors
 => [
  #<Class:Crossfield>,
  #<Class:FederationShip>, 
  #<Class:Object>, 
  #<Class:BasicObject>, 
  Class, 
  Module, 
  Object, 
  Kernel, 
  BasicObject
]

It does however, inherit from the singleton classes of its parents, which include the object, which means any methods that were defined on its parents would be accessible on it too. For instance, the prefix method defined earlier on FederationShip would also be accessible on Crossfield, a child class:

class << FederationShip
  def prefix
    'NCC'
  end
end

class Crossfield < FederationShip
end

Crossfield.prefix
 => "NCC"

So, if a class was an object that had a singleton class, does a singleton class have a singleton class too?

Why yes!

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

And these are its ancestors:

Crossfield.singleton_class.singleton_class.ancestors
 => [
  #<Class:#<Class:Crossfield>>,
  #<Class:#<Class:FederationShip>>,
  #<Class:#<Class:Object>>,
  #<Class:#<Class:BasicObject>>,
  #<Class:Class>,
  #<Class:Module>,
  #<Class:Object>,
  #<Class:BasicObject>,
  Class,
  Module, Object, Kernel, BasicObject]

This is quite a bit to unpack here, but essentially, since a singleton class of a singleton class contains the methods available to singleton classes, the singleton class neccessarily inherits from the singleton class of the class Class itself!

Which means defining methods on the Class class essentially defines it on every class, which is what we expect.

class Class
  def meow
    'meow'
  end
end

class A
end

A.meow
 => 'meow'

Back to the discovery instance, the class << syntax can also be used on instances since instances are no different from classes:

# This does exactly the same thing as what we did right at the top of this post.
class << discovery
  def goto(location)
    puts "Spore Jump to #{location}"
  end
end

Which is probably cleaner syntax if you wanted to only operate on particular instances at a time.

Hopefully this post would have helped explain how Ruby allows you to define class and instance methods, and how both kinds of methods are essentially the same thing, but on different singleton classes that inherit from different singleton classes.

If you want to learn more about this topic, Metaprogramming Ruby is a great read that goes into more detail.

We are giving out a Ruby Cheatsheet

Picture of the Ruby Cheatsheet cover

Many people use Ruby just fine not knowing the intricacies of Singleton Classes, but while working on our Ruby apps we have discovered over the course of writing Ruby code that it has a lot of useful features.

Some of it is less well known than others, and are extremely useful in specific places. We have attempted to compile these, including info about Singleton Classes and more into a small booklet called The Ruby Cheatsheet that we will be handing out at RubyKaigi 2019!

Come over and have a chat at our booth on the fifth floor if you are there!

Looking for a Rails developer
Degica is looking for a Rails developer to work with our dev team. Checkout the link for more information.