Tuesday, January 8, 2008

Singleton methods in Ruby

I am not a guru in any specific language. I work for a firm where technology keeps changing with projects. This time its again RoR. Before this I have worked on couple of RoR projects. With each project it seemed to me as if I was doing the same repetitive job, store and fetch data from database. So this time I decided to go a bit further and explore the language basics together with the new project.

After having a quick look at the rails core I got the first thing to start with.
class Foo
  class << self
    def bar()
      self.name
    end
  end
end

After googling around a bit I figured out that it's a way to create and bind a class to a specific instance or object. This binding class is called eigenclass, or more commonly a singleton class. Similarly, methods defined in a singleton class are called singleton methods. There is another alternative syntax for defining singleton methods.

irb(main):001:0> duck = Object.new
=> #
irb(main):002:0> 
irb(main):003:0* def duck.speak
irb(main):004:1>   'quack! quack!'
irb(main):005:1> end
=> nil
irb(main):006:0> duck.speak
=> "quack! quack!"
irb(main):007:0> 

Only the specific instance with singleton class has access to its singleton methods. The other instances from the same object's class don't share the added class and hence behave normally.

irb(main):001:0> duck = Object.new
=> #
irb(main):002:0> class << duck
irb(main):003:1>   def speak
irb(main):004:2>     'quack! quack!'
irb(main):005:2>   end
irb(main):006:1> end
=> nil
irb(main):007:0> duck.speak
=> "quack! quack!"
irb(main):008:0> 
irb(main):009:0* cat = Object.new
=> #
irb(main):010:0> cat.speak
NoMethodError: undefined method `speak' for #
This was all about the general idea. Lets move to some more depth beginning with a generic definition.
In Ruby, a singleton class is an instance specific anonymous virtual class that is created on the fly to hold the object specific behaviors (or methods). It is anonymous in the sense that it never appears in a list of objects returned from methods such as Module#ancestors or ObjectSpace::each_object, and virtual since it cannot be sub-classed or instantiated. It's only purpose is to provide a place to mount methods and instance variables that are uniquely associated with the specified object.

All the classes that Ruby creates automatically are marked as singleton (in class flags) internally. Also, like any other ruby class, a singleton class can also include modules.

irb(main):001:0> module BirdCharacteristics
irb(main):002:1> 
irb(main):003:1*   def can_fly?
irb(main):004:2>     true
irb(main):005:2>   end
irb(main):006:1> 
irb(main):007:1* end
=> nil
irb(main):008:0> duck = Object.new
=> #
irb(main):009:0> 
irb(main):010:0* class << duck
irb(main):011:1> 
irb(main):012:1*   include BirdCharacteristics
irb(main):013:1> 
irb(main):014:1*   def speak
irb(main):015:2>     'quack! quack!'
irb(main):016:2>   end
irb(main):017:1> end
=> nil
irb(main):018:0> duck.can_fly?
=> true
irb(main):019:0> duck.speak
=> "quack! quack!"
irb(main):020:0>
Now to grab the strategy behind the singleton classes lets first look at the structure of Ruby objects and classes. Each Ruby object consists of three main components:
  • A set of flags to store the meta-data about the object (like whether the object is frozen or tainted).
  • A hash to store instance variables.
  • A reference pointer (kclass) to object's class.
A class in Ruby is an instance of class Class. So it too contains all the three components described above together with
  • A pointer (super) to the parent or super class.
  • A list of methods.
 --------------------            -------           --------------
| object             |          | class |         | Parent class |
 --------------------            -------           --------------
| flags              |     ---> |  ...  |         |              |
| instance variables |    |     | super |-------> |     super    | ---> nil
| kclass             | ---      |   _   |         |              |
 --------------------            -------           --------------

Interestingly ruby objects itself don't store any methods. All the instance methods are stored in Class objects and shared by all the instances. When a method is invoked on an object ruby interpreter first searches the object's direct class using its kclass pointer. If it is found there then the method body is returned for the evaluation, next parent (super class) in the inheritance hierarchy is looked-up. This process continues until method is found, or no parent is available i.e. Root class (super = nil) is reached. In the latter case an exception is raised.

This was fine, but things get complex when it comes to invocation of class methods. Class methods like instance methods can't be stored in classes, or more specifically Class objects. If it is so, then they would be accessible from all the class instances using normal method calls. To resolve this ruby plays a small trick. Whenever a class method definition is encountered, it internally creates a new anonymous class, adds the class method to it, and binds it with the object manipulating the klass pointer. This new class is our singleton class. To retain the original behavior of object ruby manipulates the value of super pointer in singleton class to point the actual (instantiation) class object establishing an implicit inheritance.

 --------------------            -------
| object             |          | class |
 --------------------            -------
| flags              |     ---> |  ...  |
| instance variables |    |     | super |
| kclass             | ---      |   _   |
 --------------------            -------

                        Before class method definition
                        
 --------------------            ----------------------------           -------
| object             |          |         singleton class    |         | class |
 --------------------            ----------------------------|           -------
| flags              |     ---> |             ...            |         |  ..   |
| instance variables |    |     |            super           |-------> | super |
| kclass             | ---      | [.., new_class_method, ..] |         |   _   |
 --------------------            ----------------------------           -------

                        After class method definition

Now when a method invocation request is received ruby first checks the singleton class. If method is found then it is executed, else search is forwarded to the actual class using the super pointer in singleton class, followed by super class chain in case of failure.

All the methods defined for a singleton class are called singleton methods. The is another alternative method (other than the one described in the beginning) for defining singleton methods.

No comments: