If you learned object oriented programming from one of the more static languages such as C++ or Java, the dynamic nature of Ruby may seem magical and elusive. After running into the syntax dedicated to meta-programming, you may have been left scratching your head, or at least wondering what's happening behind the scenes. Singleton classes, not to be confused with the singleton design pattern, can easily be placed into this head scratching category.
The name itself is confusing, leading people to create alternative names such as: object-specific classes, anonymous classes, and virtual classes. Anonymous classes is one of the better names, but since the source code to the Ruby interpreter uses the term singleton, that's what I'm going to stick with.
Truth be told, singleton classes aren't really that difficult to understand. In this excerpt from my Accelerated Ruby workshop, I remove the mystical fog surrounding the singleton class, and even demonstrate how they can be useful in your day-to-day Ruby adventures.
Method Dispatching
Before we dive into the mysterious singleton underground, let's step back for a quick refresher on dynamic dispatch in Ruby. With each method call, the Ruby interpreter needs to examine the inheritance hierarchy of the receiver in order to find the method that will be executed.
foobar = Array.new
foobar.class # => Array
foobar.size # => 0
In the last statement above, the size
method was called on the foobar
object. You can also say that the foobar
object was the receiver of the size
message. It's the class of the receiver where the interpreter will start its search for the size
method, which in this case is the Array
class.
If the Array
class doesn't contain the size
method, the search will continue up the hierarchy until it's found. If the method isn't found at the top of the hierarchy, the search is aborted, and the receiver is sent the method_missing
message. Luckily for us, the Array
class does indeed have a size
method, and in the example above, it returned zero.
Figure 1 illustrates how an object is connected to its class, and how a class is connected to its parent class, also known as its super.
Figure 1. Dynamic Dispatch Without Singletons |
Enter the Singleton Class
Instead of working our way through some wordy and complicated description of what a singleton class is, let's just dive right in and see what it does.
foobar = Array.new
def foobar.size
"Hello World!"
end
foobar.size # => "Hello World!"
foobar.class # => Array
bizbat = Array.new
bizbat.size # => 0
As in the previous example, a new instance of the Array
class is created and safely tucked away into a variable named foobar
. Then, without warning, we have a funny looking method definition.
Ruby, being the flexible language that it is, allows you to explicitly specify a receiver when defining methods. That is, we can tell Ruby what object will acquire the new method. This syntax shouldn't look too unfamiliar, since it's similar to the syntax used when creating class methods. However, in the case above, we're adding a method to the foobar
object.
That's right, that method definition above creates a method that only exists for a single object, not for a class of objects. As you can see from the example code above, other objects of the Array
class do not have this new size
method, they're still using the one defined in the Array
class.
That cheeky little foobar
object has now been transformed to something slightly different than what it was before. How is this possible? What is it that makes this foobar
object so special that it gets to have methods that no other object has? If you said "singleton class", you'd be correct. When you add a method to a specific object, Ruby inserts a new, anonymous class into the inheritance hierarchy as a container to hold these types of methods.
Figure 2. Dynamic Dispatch With Singletons |
This new singleton class in the foobar
inheritance hierarchy has some special properties. As mentioned before, the singleton class is anonymous, it has no name and is not accessible through a constant like other classes. You are able, however, to access the singleton class using some trickery, but you can't instantiate a new object from it.
Object instantiation is prevented by the interpreter for any class that has a special singleton flag set on it. This internal flag is also used is when you call the class
method on an object. You would expect that the singleton class is returned from that method call, but in fact the interpreter skips over it and returns Array
instead.
Another very interesting side effect of the singleton class is that you can use the super
method from within your singleton method. Looking back to the code above, we could have called the super
method from inside the singleton method. In that case, we would be calling the size
method from the Array
class.
Speaking of side effects, if you're curious whether or not an object has a singleton class, there is an introspective method called singleton_methods
that you can use to get a list of names for all of the singleton methods on an object.
Finally, a word of caution. Once you've created a singleton class for an object, you can no longer use Marshal.dump
on that object. The marshal library doesn't support objects with singleton classes:
>> Marshal.dump(foobar)
TypeError: singleton can't be dumped
from (irb):6:in `dump'
from (irb):6
Since some of the distributed programming libraries use the marshal calls to move objects around machines, you might run into the error message above. And now you know what it means.
More Ways to Skin a Singleton
It shouldn't be surprising that Ruby has several ways to create a singleton class for an object. Below you'll find no less than three additional techniques.
Methods From Modules
When you use the extend
method on an object, to add methods to it from a module, those methods are placed into a singleton class.
module Foo
def foo
"Hello World!"
end
end
foobar = []
foobar.extend(Foo)
foobar.singleton_methods # => ["foo"]
Opening the Singleton Class Directly
Here comes the funny syntax that everyone has been waiting for. The code below tends to confuse people when they see it for the first time, but it's pretty useful and fairly straightforward.
foobar = []
class << foobar
def foo
"Hello World!"
end
end
foobar.singleton_methods # => ["foo"]
Anytime you see a strange looking class definition where the class
keyword is followed by two less than symbols, you can be sure that a singleton class is being opened for the object to the right of those symbols.
In this example, the singleton class for the foobar
object is being opened. As you probably already know, Ruby allows you to reopen a class at any point, adding methods and doing anything you could have done in the original class definition. As with the rest of the examples in this section, a foo
method is being added to the foobar
singleton class.
Evaluating Code in the Context of an Object
If you've made it this far, it shouldn't be shocking to see a singleton class created when you define a method inside an instance_eval
call.
foobar = []
foobar.instance_eval
def foo
"Hello World!"
end
EOT
foobar.singleton_methods # => ["foo"]
Practical Uses of Singleton Classes
Before you chalk this all up to useless black magic, let's tie everything off with some practical examples. Believe it or not, you probably create singleton classes all the time.
Class Methods
While some object oriented languages have class structures that support both instance methods and class methods (sometimes called static methods), Ruby only supports instance methods. If Ruby only supports instances methods, where do all those class methods you've been creating end up? Why, the singleton class of course.
This is possible because Ruby classes are actually objects instantiated from the Class
class. Their names are constants that point to this object instantiated from the Class
class. While this object holds the instance methods for objects instantiated from it, its so-called class methods are kept on a singleton class.
class Foo
def self.one () 1 end
class << self
def two () 2 end
end
def three () 3 end
self.singleton_methods # => ["two", "one"]
self.class # => Class
self # => Foo
end
Two of the three methods defined in the code above are class methods, and therefore go into a singleton class. Left as an exercise for the reader is the inheritance hierarchy for the object that the Foo
constant references.
Test Mocking
Mocking is a popular testing technique that allows you to stub out method calls for an object or class, forcing them to return a specific value, or ensuring that they are called a specific number of times. While there are several good mocking libraries available for Ruby, wouldn't it be nice to know how they work?
In the example below, there is a Foo
class with two instance methods. The available?
method is dependent on the results of the status
method. What do you do if you need to verify that the available?
method works correctly, given the varying results which the status
method could return? Mocking, and singleton classes to the rescue.
require 'test/unit'
class Foo
def available?
status == 1
end
private
def status
rand(1)
end
end
class FooTest < Test::Unit::TestCase
def setup
@foo = Foo.new
end
def test_available_with_status_1
def @foo.status () 1 end
assert(@foo.available?)
end
def test_available_with_status_0
def @foo.status () 0 end
assert(!@foo.available?)
end
end
0 Comments