Singleton Classes: The Class' Mysterious, Estranged Uncle

As we continue to climb further down the rabbit hole that is object oriented programming, the sheer magnitude of my ignorance is becoming more clear everyday - and I have a feeling I should start getting comfortable existing in this state of “conscious incompetence” for a while. One thing I continue to find myself uncomfortable with is separate class object interactions - the thought of doing another “Artist-Song-Genre” lab makes me dry-heave. As such, I thought it would be a good exercise to try and dig into a related topic and work to better understand class interactions.

We’ve seen the use of singleton methods before, and on the surface they look pretty straightforward - you simply define a particular method directly on the desired object, after which only that object can have that method called on it:

1
2
3
4
5
6
actor = "Leonardo DiCaprio"
def actor.oscar
  self + " will never win an Oscar"
end
actor.oscar                       #==> "Leonardo DiCaprio will never win an Oscar"
"Matthew McConaughey".oscar  #==> NoMethodError: undefined method `oscar' for "Matthew McConaughey":String

Makes sense, right? Visually, you can see what’s going on. Take a moment and consider something we’ve discussed a number of times in class - the concept of abstraction in our code. The strategy above, while legitimate, is about as literal as we could have made it. You may not be surprised to learn that Ruby has an answer for us - and it is related to where a singleton method actually lives.

It is here we are introduced to a shadow-like, creepy, estranged-uncle class. At instanciation, every object is actually born with two classes - the class that it is an instance in, and its singleton class. At the time of their creation, they have no name, and are effectively anonymous until explicitly called upon. David A. Black, of the “Well Grounded Rubyist,” has a slightly less sinister-sounding explanation:

You can think of an object’s singleton class as an exclusive stash of methods, tailor-made for that object and not shared with other objects—not even with other instances of the object’s class. - David A. Black

The next questions to explore are when and how we as programmers should be interacting with our objects' singleton classes. Imagine you have an object - an instance of a particular class that you know you want to act in unique ways - creating a whole collection of singleton methods for this class instance would look terribly messy and as mentioned before, wouldn’t be very abstract - if your program had to change down the road, you’d have to make sure you changed the object keyword on every single one.

Ruby, of course, has an elegant and efficient solution for this problem. The singleton class for a particular object can be defined for multiple methods using the following syntax:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Person
  def lunchtime
    "I eat hamburgers for lunch."
  end
end

chad = Person.new
roger = Person.new
chad.lunchtime     #==> "I eat hamburgers for lunch."
roger.lunchtime    #==> "I eat hamburgers for lunch."

class << roger
  def lunchtime
    "I eat hay for lunch."
  end

  def bedtime
    "I sleep in a stable."
  end

  def confession
    "I'm actually a horse."
  end
end

chad.lunchtime     #==> "I eat hamburgers for lunch."
roger.lunchtime    #==> "I eat hay for lunch."
chad.bedtime       #==> NoMethodError: undefined method `bedtime' for #<Person:0x007fa98a1fdfe8>
roger.bedtime      #==> "I sleep in a stable."
roger.confession   #==> "I'm actually a horse."

As you can see, by using the singleton class assignment notation to ‘require’ it, we’re able to bring Roger’s singleton class and its associated behaviors out of the shadows in an efficient way.

A frequent use of this concept and syntax in Ruby programming involves streamlining something we already have some experience with - defining class-specific methods. Up until this point, we’ve assigned class methods in a very similar way to that of singleton methods:

def self.all; end or def self.most_expensive; end

This works, but by incorporating the syntax we just learned, we can streamline class method assignment by relying on its singleton class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Artist

  class << self
    def all
      @@all | |= [ ]
    end

    def create(artist_name)
      new_artist = Artist.new(artist_name)
      new_artist.save
      new_artist
    end

    def destroy_all
      all.clear
    end
  end
  # begin regular class methods
  def add_song(song)
    . . . .
  end
  . . . .
end

In this example, because we’re assigning the Artist’s singleton class inside the body of the class, we’re able to utilize ‘self, ’ and save ourselves some typing and potentially unorganized code. class << self inside the body is equivalent to class << Artist outside the body.

The last thing we’ll look at is, which is likely obvious at this point, is how singleton classes fit into the method lookup chain:

As you can see to the left, the object (an instance of class D) first checks its singleton class for the method in question before any modules or its parent class. From here, the list of possible uses goes on - you are able to even able to incorporate modules in your singleton classes for further class instance customization…but we’ll leave that for another day.