ruby ruminations – singleton class

some call it singleton class, some metaclass or even eigenclass.
in this blog entry i will give some explanation about the concept of singleton class (which i will call it during this post) and some (more or less useful) examples of its application.

you’re one-of-a-kind

as you may know, ruby lets you enhance single objects by adding a new method to just one instance of an arbitrary class, leveraging this specific object to a real ‘singleton’ (in another sense, in contrast to the well known singleton pattern). since all methods are defined and housed in the objects class’, such new added methods also have to be ‘append’ to and hence reside in the objects class.

lets say we want to add a method palindrome? to only one specific instance of a string:

aString = "never odd or even"

class << aString
    def palindrome?
        self.gsub(/\s/, '') == self.reverse.gsub(/\s/, '')
    end
end

aString.palindrome?
# => true

only this single object of String now offers this new method palindrome? (a call to any other instance of String would result in a NoMethodError)

now one could ask, where this new method is going to reside. it can’t be send to the class String. if so, then all String objects would offer this method. that’s where our singleton class comes into the game …

especially for you

whenever a method is added to a single object in the above indicated way, ruby will create an extra class especially for that single object! and exactly this one is – you guessed right – our so called singleton class!

this singleton class is a virtual one, since it never appears as a fully-flegded member in the list of classes (remember that all classes are objects, which are accessible by their names as constants). ruby will insert this singleton class as the direct (again – virtual) class of the object. the former direct class – in the examples case the class String – will slide one level up, so the singleton class ‘sits’ between the object and the original class of the object.
now, whenever a method call (message) is send to the object, ruby will (as always) look at the direct class of the object, wheter the method is defined within that class. if so, ruby is happy and executes that method. if not, ruby will go to the ancestor (super) class (which is now the original classof the object) in order to track the message call and so on.

everywhere i go

we now saw the mechanism of how ruby is able to add methods to single instances. going one step further we could ask ourself if it’s possible to use this mechanism inside a class. we could for example offer a convenient instance method palindromize() inside the class of String in order to add the palindrome?() method to arbitrary instances of String in a quick and easy way. and of course, it’s possible:

class String
    def palindromize
        class << self
            def palindrome?
                self.gsub(/\s/, '') == self.reverse.gsub(/\s/, '')
            end
        end
    end
end

s = "otto"

s.respond_to?( :palindrome? )
# => false

s.palindromize
s.respond_to?( :palindrome? )
# => true

note, that we now use self to ‘append’ the new method. since we are inside an instance method, self refers to the object itself (on which the instance method is called) and hence the effect is the same as if you would append a new method to a single object explicitly outside a class (like in the first example)! we refer to a specific object instance in both cases.

catch me if you can

one interesting point is the scope of self inside of class << self … end. as you may have suspected, we are in scope of that ominous singleton class, and you’re right …

class String
    def palindromize
        class << self
            puts "#{self}"      # => #<Class:#<String:0x2b418e0>>
            ...
        end
    end
end 

as you can see, puts prints the ‘signature’ of the singleton class – in the example’s case the singleton class for the String object #<String:0x2b418e0> on which the method was called.
this brings us to the point where we could dare a look at a often mentioned method (mostly even called singleton_class() or even metaclass() or eigenclass()) and understand easily what’s going on there:

class String # could be an arbitrary class
    def singleton_class
        class << self; self; end
    end
end

this instance(!) method is a convenient way to access the singleton class of an object on which the method gets called. as you can see (and nothing new to us), we refer to the singleton class again (class << self), but this time not to define a new method inside the scope of that singleton class but to return the singleton class of that object itself (with self being the last evaluated expression of that method).

i count on you

catching that singleton class as an object gives us completely new options towards a way of metaprogramming or at least a kind of generic programming. for example, it’s easy to add this method inside a module together with some generic functions that operate on the singleton class of an object:

module Appendable
    def singleton_class
        class << self; self; end
    end

    def append_method( method_name, &prc )
        singleton_class.class_eval do
            define_method( method_name, prc )
        end
    end
end

so what’s going on here?
first of all we have the above mentioned method aside that allows us to refer to the singleton class of an object. we access the singleton class inside the method append_method(), which takes a method name and a proc. both arguments will constitute a new method that will be appended to a single object via its singleton class.
since we define such a method in a completely generic way in that the name of the method to append is dynamic, we use class_eval (so we can define parts of that method in a generic way and let ruby evaluate the whole expression).

now we’re able to append methods very dynamic to objects of an arbitrary class which includes that module:

class Prototype
    include Appendable
end

p = Prototype.new
p.append_method( :say_hello ){|n| puts "hello #{n}" }
p.say_hello( 'Dave' )
# => hello Dave

using include (in contrast to extend) includes the modul’s methods as instance methods. that’s what we need, since we want to catch an objects singleton class. having done so enables us to append arbitrary methods to our Prototype class in a dynamic way. calling the modul’s append_method(), passing a method name and a block will lead to the dynamic added method (remember, that the last argument &prc inside the argument list of append_method() will implicit call to_proc which will transfer the given block into a proc object).

no magic at all

as you’ve seen, there’s no magic about this often mentioned singleton class, metaclass or eigenclass. it’s one of rubys mechanisms which allows for dynamic programming and high flexibility.
once you have seen and understand the semantics behind these concept, it should be easy to build your own functionality on top of this instrument …

Advertisements
Posted in ruby. 9 Comments »

9 Responses to “ruby ruminations – singleton class”

  1. Marcus Crafter Says:

    Nice one mate – I also found Why’s article quite helpful too in understanding metaclasses: http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html

    Cheers,

    Marcus

  2. Anonymous Says:

    hi. thanks for the clear explanation. i was searching for the explanation of (class << self; self; end) and you did it very well.

  3. Mario Gleichmann Says:

    thanks for your feedback.
    i once had the same question – this blog entry is the result ;o)

  4. Dr J Says:

    excellent explanation of singleton classes. Thanks for contributing to the Ruby community

  5. toisteabita Says:

    Машины – вот счастье!))

  6. rusonlineinvest Says:

    Слышал продолжение телепузиков снимают

  7. Ruby beginnings for a pet project « Sagar Sunkle's Blog Says:

    […] and even a singleton. Used via class << instance_name … end, it indicates that Ruby creates an eigenclass around that instance and endows that class with whatever code comprising the … in the snippet above. One could think […]

  8. bet365 Says:

    hi I was luck to look for your blog in digg
    your subject is superb
    I learn a lot in your theme really thank your very much
    btw the theme of you website is really impressive
    where can find it

  9. bet365 Says:

    how are you I was fortunate to discover your theme in digg
    your post is excellent
    I learn a lot in your Topics really thanks very much
    btw the theme of you site is really impressive
    where can find it


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: