söndag, september 24, 2006

The Ruby singleton class

After my post on Meta-programming techniques I got a few comments and questions about the singleton-class. This feature seem to be quite hard to understand so I have decided that I will try to clarify the issue by first describing what it is, and then detail why it is so useful. This entry will be concept-heavy and code-light.

What it is
A child with many names, the singleton class has been called metaclass, shadow class, and other similar names. I will stay with singleton class, since that's the term the Pickaxe uses for it.

Now, in Ruby, all objects have a class that it is an instance of. You can find this class by calling the method class on any object. The methods an object respond to will originally be the ones in that objects class. But as probably know, Ruby allows you to add new methods to any object. There are two syntaxes to do this:
 class << foo
def bar
puts "hello world"
end
end
and
 def foo.bar
puts "hello, world"
end
To the Ruby interpreter, there is no difference in this case. Now, if foo is a String, the method bar will be available to call on the object referenced by foo, but not on any other Strings. The way this works is that the first time a method on a specific object is defined, a new, anonymous class will be inserted between the object and the real class. So, when I try to call a method on foo, the interpreter will first search inside the anonymous class for a definition, and then go on searching the real class hierarchy for an implementation. As you probably understand, that anonymous class is our singleton class.

The other part of the mystery about singleton classes (and which is the real nifty part) is this. Remember, all objects can have a singleton class. And classes are objects in themselves. Actually, a class such as String is actually an instance of the class Class. There is nothing special about these instances, actually. They have capitalized names, but that's because the names are constants. And, since every class in Ruby is an instance of the class Class, that means that what's called class methods, or static methods if you come from Java, is actually just singleton methods defined on the instance of the class in question. So, say you would add a new class method to String:
 def String.hello
puts "hello"
end

String.hello
And now you see that the syntax is actually the same as when we add a new singleton method to any other object. This only difference here is that that object happens to be an instance of Class. There are two other common ways to define class methods, but they work the same way:
 class String
def self.hello
puts "hello"
end
end

class String
class << self
def hello
puts "hello"
end
end
end
Especially the second version needs explaining, for two reasons. First, this is the preferred idiom in Ruby, and it also makes explicit the singleton class. What happens is that, since the code inside the "class String"-declaration is executed in the scope of the String instance of Class, we can get at the singleton class with the same syntax we used to define foo.bar earlier. So, the definition of hello will happen inside the singleton class for String. This also explain the common idiom for getting the singleton class:
 class << self; self; end
There is no other good way to get it, so we extract the self from inside a singleton class definition.

Why is it so useful for metaprogramming?
Obviously, you can define class methods with it, but that's not the main benefit. You can do many metaprogramming tricks with it, that are impossible without. The first one is to create a super class that can define new class methods on sub classes of itself. That is the use I show cased in my earlier blog entry. The problem is that you can't just use self by itself, since that only gives the class instance. This code with results show the difference:
 class String
p self
end # => String

class String
p (class << self; self; end)
end # => #<Class:String>
And, if you want to use define_method, module_eval and all the other tricks, you need to invoke them on the singleton-class, not the regular self. Basically, if you need to dynamically define class methods, you need the singleton-class. This example will show the difference between defining a dynamic method with self or the singleton class:
 class String
self.module_eval do
define_method :foo do
puts "inside foo"
end
end

(class << self; self; end).module_eval do
define_method :bar do
puts "inside bar"
end
end
end

"string".foo # => "inside foo"
String.bar # => "inside bar"
As you can see, the singleton class will define the method on the class instead. Of course, if you know the class name it will always be easier to avoid having an explicit singleton class, but when the method needs to defined dynamically you need it. It's as simple as that.

9 kommentarer:

Peter sa...

This is tricky...

As far as I understand, singleton.class_eval do define_method [...] adds _class_ methods to the given class. But how can one add _instance_ methods to it? For example, I want to have something like this:

class Foo < BigFoo
attribute :bar, "Hello"
end

foo = Foo.new
foo.bar # => "Hello"

I've played around a bit with it and I could only come up with the following code so far:

class BigFoo
def attribute(name, value
singleton = class << self; self; end
singleton.class_eval "def #{name}; value; end"
end
end

Is there a better way to achieve the same result?

lopex sa...

Then no singleton class is needed since self will be the class you call the attribute method from

class BigFoo
def self.attribute(name, value)
define_method(name){value}
end
end

class Foo < BigFoo
attribute :bar, "Hello"
end

foo = Foo.new
p foo.bar # => "Hello"

Mariano sa...

Great stuff. Please keep it up.

Something about continuations would be nice ;-)

yan sa...

Try why's metaid.rb. It makes this very easy: http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html

Tomas sa...

Very nice, I learned quite a bit from this. Keep it up!

Sam sa...

Hi there, sorry to sound a bit dumb, but could you just briefly explain the difference between

`String` and `# gt Class:String lt`

(the comments parser wouldn't let me use the gt, lt symbols, so i just substituted them with abbreviations)

i briefly tried to compare them, and the only difference I found was that `# gt Class:String lt` had an additional method called nesting, which i believe is a method of class Module. But that just confused me further :)

Anonym sa...

The real term for the so-called 'singleton class' is 'pouch'!

Join the marsupial revolution!

Brendan Baldwin sa...

I was working on a similar issue of adding a method to an instance of an object (i.e. a singleton method).

I just posted my solution to my blog but I would love to know if there's a better or less expensive one:

http://www.usergenic.com/2006/12/21/dynamic-instance-methods/

Sergio sa...

You don't need (class << self; self; end) to create instance methods and class methods for a String.

I may be missing something, because this works with no problems, even with inheritance.

class String

def self.create_instance_method
def foo
puts "inside foo"
end
end

def self.create_class_method
def self.bar
puts "inside bar"
end
end
end

class Pela < String; end

s = String.new("aaa")
p = Pela.new("bbb")

Pela.create_class_method
Pela.bar # OK
String.bar # ERROR

Pela.create_instance_method

s.foo # OK (hummmmm)
p.foo # OK