Aman King

Metaclass in RubyControl PanelChange LogBrowse PagesSearch?

Metaclass in Ruby

After writing about the Singleton class in Ruby, it is time to write about the Metaclass.

Note that some people use "metaclass" to mean a normal singleton class (aka eigenclass) but that is incorrect. The Ruby metaclass is a special type of singleton class, one for a Ruby class object (hence the term "metaclass", I guess).

Recapping what we know about the singleton class, in the following example we can guess where the definition of the method find_by_name goes:

class Person
  def self.find_by_name(name)
    puts "finding by name: #{name}"
    # ...
  end
end
 
Person.find_by_name('Aman') # => 'finding by name: Aman'

Yes, find_by_name actually gets defined on the singleton class of the class object referenced by Person, which is why we can invoke Person.find_by_name('Aman') but not Person.new.find_by_name('Aman').

This is how a method invoked on a class object is looked up:

# ... in continuation from previous snippet
 
Person.class # => Class
 
# let 'blah mean the singleton class of blah
Person.find_by_name('Aman') # method looked up in 'Person; found; invoked
Person.new # method looked up in 'Person; not found; looked up eventually in Class (Person is an instance of class Class); found; invoked

The above look up sequence should not be surprising given what we know about the workings of singleton classes. Now, let's consider this:

# ... in continuation from previous snippet
 
class Employee < Person
  def self.find_by_employee_id(employee_id)
    puts "finding by employee id: #{employee_id}"
    # ...
  end
end
 
Employee.find_by_employee_id(10) # => 'finding by employee id: 10'

Again, we know that find_by_employee_id gets defined on Employee's singleton class, which is why Employee.find_by_employee_id(10) works. But what about Employee.find_by_name('Aman') -- will it work? Let's find out...

# ... in continuation from previous snippet
 
Employee.find_by_name('Aman') # => 'finding by name: Aman'

Yep, it worked!

And it does seem logical, doesn't it? An employee is a person; so the way you search for a person should work to find an employee too.

Given the above expectation, this is how the invoked method is found for class objects:

# ... in continuation from previous snippet
 
Employee.find_by_employee_id(10) # method looked for in 'Employee; found; invoked
Employee.find_by_name('Aman') # method looked for in 'Employee; not found; looked for in 'Person; found; invoked
Employee.new # method looked for in 'Employee, then in 'Person, then in 'Object, then in Class (not 'Class); found; invoked
Employee.foo # method looked for in 'Employee, then in 'Person, then in 'Object, then in Class; not found; NoMethodError

The way Ruby makes the above possible is exactly how metaclasses are different from normal singleton classes:

  1. a metaclass, ie, a singleton class of a class object, allows looking up methods in the class object's superclass's singleton class and so on up the inheritance hierarchy (in the above example, remember that Person has Object as its implicit superclass), finally looking up in the class Class. If it were a normal singleton class, the method invoked would have been looked up in the singleton class and then immediately in the class of the class object, ie, Class.
  2. every class object created has its corresponding metaclass created immediately, so that (1) the metaclass is correctly configured according to the inheritance hierarchy, (2) linking of a future subclass's metaclass to the superclass's metaclass will be quick/optimized. Note that for a normal object, the corresponding singleton class is created on the first need for it but not otherwise.

I hope my attempted explanation clarifies why we need a special metaclass implementation in Ruby and how it is different/enhanced with respect to the normal singleton class.

(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:41 Mon, 4 May 2009 by AmanKing. Accessed 547 times Children What Links Here share Share Except where expressly noted, this work is licensed under a Creative Commons License.