Aman King

Singleton class...Control PanelChange LogBrowse PagesSearch?

Singleton class in Ruby

The singleton class is an often discussed topic among Rubyists, especially new ones who are gradually learning about Ruby's metaprogramming features. There are a number of blog posts or articles already about this... I'll just add one more. Smile

This is my take on the Singleton class, presented in the way I typically explain it to new Ruby enthusiasts.

Firstly, I'll assume that you know that (almost) everything is an object in Ruby, and that includes classes.

Next, we need to know that objects can have behavior of their own that are not shared with other similar objects.

class MyClass
  def blah
    'blah'
  end
end
 
obj = MyClass.new
 
obj.hi # => NoMethodError
 
def obj.hi
  'hi'
end
 
obj.hi # => 'hi'
 
another_obj = MyClass.new
another_obj.hi # => NoMethodError
 
obj.class # => MyClass
another_obj.class # => MyClass

The above code shows one way to add instance-specific behavior. Interesting thing to note is that the new method is invokable only from the instance it was defined on and not from other instances of the same class. This means that the method was not added to the class of the instance.

Does that mean that an object itself can hold method definitions?

Well, the answer is no (unless it's an object that represents a class or a module). One of the reasons the concept of classes exists in Ruby is that they are meant to hold method definitions and act as blueprints for their instances, ie, they determine what methods can be invoked on their instances.

So where did the method hi go?

Yes, that's correct, it went into the singleton class of the instance. This hidden class is different from the class the instance was created from and is a Ruby implementation detail that is typically not revealed to anyone (there is only one way to get to the singleton class, which we'll talk about in a while). This is the reason it is sometimes called ghost class or anonymous class or shadow class. Some people also refer to it as metaclass but since it's not always a "class for a class" (but is more like a class for an object), this term is misleading. Another popular name is eigen class (which means "own class" in German).

The singleton class is created for an object as soon as the Ruby interpreter needs to add instance-specific behavior for that object (but not before that). Going forward, if more methods need to be added to the same object, its already-created singleton class is used. Also, more instances cannot be created using a particular singleton class (its new method raises an error). Because of this one-to-one relationship between an object and its singleton class, the word 'singleton' is used (I think).

So, what is the way in which one can get access to an object's singleton class?

# ... in continuation from previous snippet
 
obj_singleton_class = class << obj; self; end
obj_singleton_class.ancestors # => [MyClass, Object, Kernel]
MyClass.ancestors # => [MyClass, Object, Kernel]

Here class << obj; self; end is the key: anything written after class << obj and before the corresponding end is evaluated against the context of the singleton class of obj, ie, self points to the singleton class.

In the above snippet, we return self, getting a reference to it in the variable obj_singleton_class. We then see that the singleton class fakes the same ancestry as the original class of the object. This implies that when a method is invoked on an object, Ruby first looks for the method definition in the object's singleton class (if it exists), if not, Ruby then continues looking up the normal inheritance hierarchy.

# ... in continuation from previous snippet
 
obj.hi # method looked for in singleton class; found; invoked
obj.blah # method looked for in singleton class; not found; looked for in MyClass; found; invoked
obj.xyz # method looked for in singleton class, MyClass, Object, Kernel; not found; obj.method_missing() called, raising NoMethodError

Now hopefully we have understood how singleton classes work.

Let's quickly look at two other ways in which we could have added instance-specific behavior to an object:

class << obj
  def hi
    'hi'
  end
end

obj.instance_eval do
  def hi
    'hi'
  end
end

The former one should be clear from what has already been explained. The latter is tied to how def works with instance_eval (I'll probably cover this in another blog post).

Now, before concluding, let's take a step back and see if we've seen the syntax discussed so far, before. You'll probably recognize their use in defining class-level methods:

class MyClass
  def MyClass.my_class_method1
    'class method 1'
  end
 
  def self.my_class_method2
    'class method 2'
  end
 
  class << self
    def my_class_method3
      'class method 3'
    end
  end
end

And yes, you've guessed right: all class methods go into the singleton class of the object representing the class, in this case, the object referenced by the constant name: MyClass (remember classes are also objects). After all, these class method definitions need to go somewhere, and in such a way that the methods don't become part of the class's instances (ie, they aren't instance methods) nor do the methods go to the super class.

This particular usage of singleton classes can be called as metaclass but according to what we've discussed, they don't seem to have anything different from normal singleton classes. That said, there is a difference, about which you can read more here: Metaclass in Ruby

Singleton classes are fun! Enjoy exploring the uses of it! Smile

(For more details, I recommend reading fellow-TWer Patrick Farley's Ruby internals blog series.)

Comments

Talk
Tags: technology:ruby, technology:coding Last modified 01:42 Mon, 4 May 2009 by AmanKing. Accessed 1,022 times Children What Links Here share Share Except where expressly noted, this work is licensed under a Creative Commons License.