Posterous theme by Cory Watilo

The Ruby Metaclass

The ruby metaclass (also known as the Singleton class) is a very commonly misunderstood ruby language construct.

Lets look at a simple class definition:

class Dog
  def bark
    puts "woof woof!"
  end
end

The class Dog contains the instance method bark. This is pretty self-explanatory.

What happens when you define a class with class methods (also known as static methods).

In ruby, everything is an object. That means classes are objects too.

class Dog
  def self.bark
    puts "woof woof!"
  end
end

The Dog class above is actually an instance of Class.

> Dog.__id__
=> 2152689112 
> Dog.class
=> Class 
>

If the Dog class contains instance methods, what class contains the Dog’s class methods?

You might at first think Class class contains the Dog class methods. If is true, all instances of Class should contain bark method right? That wouldn’t really make sense if it behaved like that would it?

Introducing the Metaclass (also known as the Singleton class)

In between Class and Dog is a class called the Metaclass. An object’s metaclass is a Singleton class that objects inherits it’s methods from. The reason why it is so confusing is primarily due to the fact that they are invisible. You can, however, get a hold of the metaclass:

> metaclass = class << Dog; self; end
=> #<Class:Dog> 
> metaclass.instance_methods
=> [:bark, :allocate, :new, :superclass, :freeze, :===, :==, :<=>, :<, :<=, :>, :>=, :to_s, :included_modules, :include?, :name, :ancestors, :instance_methods, :public_instance_methods, :protected_instance_methods, :private_instance_methods, :constants, :const_get, :const_set, :const_defined?, :const_missing, :class_variables, :remove_class_variable, :class_variable_get, :class_variable_set, :class_variable_defined?, :module_exec, :class_exec, :module_eval, :class_eval, :method_defined?, :public_method_defined?, :private_method_defined?, :protected_method_defined?, :public_class_method, :private_class_method, :autoload, :autoload?, :instance_method, :public_instance_method, :nil?, :=~, :!~, :eql?, :class, :clone, :dup, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :frozen?, :inspect, :methods, :singleton_methods, :protected_methods, :private_methods, :public_methods, :instance_variables, :instance_variable_get, :instance_variable_set, :instance_variable_defined?, :instance_of?, :kind_of?, :is_a?, :tap, :send, :public_send, :respond_to?, :extend, :display, :method, :public_method, :define_singleton_method, :hash, :__id__, :object_id, :to_enum, :enum_for, :gem, :equal?, :!, :!=, :instance_eval, :instance_exec, :__send__]

Lets add a couple more methods to the Dog class using the metaclass:

metaclass.class_eval do
  def sit
    puts "<sits down>"
  end
end
 
Dog.sit => "<sits down>"

You may have came across code that used the following idiom to define class methods.

class Dog
  class << self
    def sit
      puts "<sits down>"
    end
  end
end

What we are actually doing above is defining a sit instance method in Dog’s metaclass.