There’s no shortage of literature on singleton classes, but it’s rare to see an explanation that covers implementation. This is unfortunate, as the implementation is not complex and familiarity with it leads to a more nuanced understanding.
A good way to look at singleton classes is to ask the question, “What is it that Ruby wants which forces the existence of a singleton class?” The answer is, “Ruby wants instance specific behavior”.
An object has only two data members, a hash to store instance variables called *iv_tbl and a reference to another struct of type RBasic called basic. RBasic is the fundamental struct in Ruby. It holds the data all Ruby “things” need for the interpreter to work with them. It’s definition is…
flags are used to store metadata about an object. An example would be a bit to indicate an object is frozen or tainted. The only other data member is the class associated with the object, stored in klass.
Note that there is nowhere in RBasic or RObject to tuck away a method body. That leaves the class associated with the klass pointer as the only place left to store the instance specific behavior. This makes a lot of sense. The entire purpose of classes in Ruby is to serve as repositories for behavior. Here Ruby finds itself in a tough spot. If the interpreter follows the klass pointer of the pirate object, it will find the Object class. Any method’s added there would be accessible to any instance of Object.
Faced with a dilemma, Ruby does something sneaky. When an attempt is made to define instance specific behavior, Ruby generates an instance of a brand new class and changes the object’s class pointer to point to this new class. It then adds the homeless instance specific behavior to the new class. Now, when the message for instance specific behavior is sent to the object, standard method dispatch kicks in, and the method body is found. This special, created on the fly, instance specific class, is called the Singleton class.
There is one more trick involved. It wouldn’t do for the object to lose all the behavior it picked up from it’s class of instantiation, so Ruby sets the super pointer of the Singleton class to point to the original class of the object. Once again standard method dispatch works just fine when searching for methods.
Below are a couple of diagrams showing the pirate object’s underlying structure before and after the speak method is defined. The prefixed apostrophe on ‘pirate can be read as “The Singleton class of pirate.”
Before Definition of Instance Specific Behavior
After Definition of Instance Specific Behavior
All of this class inheritance chain manipulation occurs in the rb_make_metaclass() function. I’ve omitted some code for clarity.
If you find all this interesting and useful, I strongly encourage you to take a look at the Ruby Hackers Guide. It’s a guide to Ruby internals written by Minero Aoki. Unfortunately, translation is an on going project that has possibly stalled out. Still, the chapters which have been translated are a wealth of Ruby internals information.