Sunday, 8 February 2009

The Singleton in Ruby

When I first read about singletons in Ruby, I assumed this was a reference to the singleton pattern; perhaps the classic example of a pattern, and in my opinion not much use (actually Ruby has a Singleton module for doing just this). However, in Ruby the singleton is something else entirely.

The singleton is a method that is attached to a single instance of a class. Here is a simple example:
s1 = 'what'
s2 = 'where'
s3 = 'when'

def s1.hello
p "Hello world"
end

class << s2
def hello
p "Hello world"
end
end


s1.hello
s2.hello
begin
s3.hello
rescue NoMethodError
p $!
end

p s1.singleton_methods
# => ["hello"]
p s2.singleton_methods
# => ["hello"]
p s3.singleton_methods
# => []

Three strings are created. The first two have singleton methods added to them in slightly different ways. The singleton methods can be invoked on that specific instance, but not on any other object of that class. Finally, the singleton_methods method is invoked to show how these methods can be listed.

Technically, the object itself does not get a new method. Objects can only hold variables, not methods. Rather, the object has a metaclass, or virtual class, and this metaclass is where the new method is. This is what class << s2 is accessing.

Class methods
You can also add singleton methods to the class, where they become class methods. The logic here is that the class is itself an object, and these methods are being added to a single instance of the Class class. This code illustrates three ways to add a singleton to a class.
def String.goodbye1
p "Goodbye world (1)"
end

class String
def self.goodbye2
p "Goodbye world (2)"
end
end

class String
class << self
def goodbye3
p "Goodbye world (3)"
end
end
end

p String.singleton_methods
# => ["goodbye3", "goodbye2", "goodbye1"]

It is interesting to note that "String" is actually a constant that holds a Class object, and this is why it is capitalised.

Note: Some believe that class << self is bad; this suggests there may be more going on here.

The singleton_methods method returns all methods for the class that are not inherited from a superclass. Use singleton_methods false to exclude methods from modules.

See also:
http://ola-bini.blogspot.com/2006/09/ruby-singleton-class.html

http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html

Struggling with Ruby: Contents Page

4 comments:

JeffMo said...

I think you may want to check how you are entering Ruby code on this blog.

The first way you are attaching a singleton method (to s1) looks correct, but the second way makes no sense to me (or to irb, when I tried it).

I'm guessing you're going for something like this:

class << s2
  def hello
    p "Hello world"
  end
end

dcsan said...

second the syntax issue. seems like an interesting + concise piece of writing tho!

F2Andy said...

JeffMo. Yes, the blog software chocked on the <<, and assued it was the start of a tag. I have corrected it, so it should be fine now. Thanks for pointing it out.

Mark Wilden said...

Ruby's use of 'singleton' is not different from other contexts. A singleton's class has only one instance. When a singleton method is added to an object, behind the scenes a new class is generated to hold that method. The object is the only instance of that class - hence, it's a singleton.