Oracle Blog

A. Sundararajan's Weblog

Metaclasses in Ruby and Smalltalk

Disclaimer: The following is my understanding (possibly
misunderstanding!) of Ruby and Smalltalk metaclasses. I am a Java programmer.
I've played a bit with Squeak
and Strongtalk.
As I said in my earlier posts, I am learning Ruby
using the JRuby 0.9.0
implementation. If you are Rubyist or Smalltalker (or both!)
and find gross errors here, please let me know [how do we call
a Java programmer?]

With class based object-oriented programming languages:

Everything is an object.
With few languages, nearly everything is an object

Every object is an instance of some class

classes "hold" methods - while instances
of classes share the methods

instances hold instance variables.

A class derives/extends from another class (called superclass)
- except for a special "root" class (typically called "Object")
whose superclass is null.

method search: When a method is called on an object, the method
is looked on it's class, if not found on superclass-of-class
and so on (till the superclass is null)

Note: Yes, I've left multiple inheritance!

Point number (1) implies every class is an object too.
If so, per point (2) every class has to be an
instance of ... well another class [called "metaclass"]. So,
what is a metaclass of a metaclass? And how do we end this seamingly "infinite" chain?

In Java, the
static methods don't have "this" object and can't access
"super" either. The "static" methods of Java are not really
connected to any object in the system -- static "methods"
are just like good old global functions except for namespace
and accessibility.

Clearly, "static" methods in Ruby are not like static methods
of Java. Class methods [as these are known in Ruby and Smalltalk
world] are very much like instance methods - can be overriden,
can call super method and have "self". "self" inside a class method is - guess what -
the class itself (recall that classes are objects!).
In fact, "self" used anywhere inside class body (except inside
an instance method) refers to the class. For example:

I mentioned class holds instance methods, if so which class would hold
class methods of a class? For example, Person "holds" the instance methods such as "whoAreYou"
Which class would hold the class methods (such as "greet") of Person class?
Is it Person.class? - no, that
can not be. Recall that Person.class is Class
- which can only "hold" methods common to all classes
(like general reflective queries such "superclass", "instance_methods"
etc.). The Class class can't hold class methods of the Person class.
If Class class had the class methods of, say Person class, then you
could call that on any class. For example, you can call "greet" class method
of Person class on any other class in the system!

Ruby's answer for this is as follows: in Ruby, every
object has an optional singleton class [also known as
exclusive class]. Whenever a method is called on an object,
first the associated singleton class, if available,
is looked up for the method. If not found, only then the
"actual" class of the object is searched [and then the usual
superclass chain search]. How would you
add singleton methods to a specific object - in other words
how would you define singleton class for an object? When
we defined class methods like Person.greet, you are
actually adding a singleton method to Person's singleton
class. In fact, you can define singleton class with the
following syntax - so that you can add multiple singleton methods in "one shot":

For every Ruby class, there is a singleton class associated
with it. The singleton class holds the "class methods" of that
Ruby class. For Person class, there is Person singleton class.
For Employee (which is a subclass Person), there is Employee
singleton class and so on. Also, Employee's singleton class
is subclass of Person's singleton class [singleton class
mirrors regular class hierarchy]

Note that every Ruby object can have an optional
singleton class. Yes, that is right -- every object, not
just class objects can have a singleton class associated
with it.

The singleton classes alongwith clone method can be
used to write prototype based
object-oriented programs (as with Self).
i.e., you don't need classes at all. You just create
objects (say using Object.new) and you specialize some
of your objects by defining singleton classes for those (note that
singleton classes are unnamed). Whenever similar behaving
objects are needed [you need a class of objects], then
clone one or more prototypical objects!

To understand Ruby class, singleton class relationship,
the following session with JRuby could help:

Smaltalk vs. Ruby metaclasses

Ruby's treatment is similar yet different from that of Smalltalk.
Ruby's singleton classes serve like
Smalltalk's metaclasses. But, unlike Smalltalk metaclasses
which have single instances, we can't create instances of
Ruby singleton classes:

Hence it has been suggested
that singleton classes be referred to as "sterile metaclasses"
It is important to note that Ruby's singleton classes
can be associated with any (ordinary) object (unlike Smalltalk). Because of this, Ruby supports prototype based object orientation.

Hmm, are you sure that in Ruby "singleton hierarchy parallels the class hierarchy"? Surely if every singleton class is a direct, anonymous, subclass of Class then the hierarchy for singleton classes will always be <singleton> - <Class> - etc. Running your Ruby example confirms my suspicion, at least with Ruby 1.8.1 under OS X.

If I understand correctly, this contrasts with Smalltalk metaclasses where, for example, "Person class: yields the single instance of the class PersonClass, a subclass of Class, and "Employee class" yields the single instance of the class EmployeeClass, a subclass of PersonClass.
(I'm not speaking from a position of authority, I have recently been trying to get my head around the same concepts, but in Smalltalk.)

As I mentioned earlier, I ran all my Ruby scripts with JRuby version 0.9.0. With that implementation, I got singleton's in the ancestor hierarchy. After your comment, I tried Ruby 8.4.2 on Windows -- the singleton classes are not shown in ancestors. It appears that Ruby wants to hide singletons completely. But, singletons do seem to have parallel mirroring hierarchy. For example, when we call

The super call in Employee.greet calls Person.greet -- which cannot be explained if the singleton hierarchy does not parallel the class hierarchy. I'll file a bug in JRuby project on the difference with the return value of ancestors() call.