Next: , Previous: Two flavors of equality, Up: Behind the scenes

6.12.3 The truth about metaclasses

Everybody, sooner or later, looks for the implementation of the #new method in Object class. To their surprise, they don't find it; if they're really smart, they search for implementors of #new in the image and they find out it is implemented by Behavior... which turns out to be a subclass of Object! The truth starts showing to their eyes about that sentence that everybody says but few people understand: “classes are objects”.

Huh? Classes are objects?!? Let me explain.

Open up an image; then type the text following the st> prompt.

         st> Set superclass!
         st> HashedCollection superclass!
         st> Collection superclass!
         st> Object superclass!

Nothing new for now. Let's try something else:

         st> #(1 2 3) class!
         st> '123' class!
         st> Set class!
         Set class
         st> Set class class!

You get it, that strange Set class thing is something called “a meta-class”... let's go on:

         st> ^Set class superclass!
         Collection class
         st> ^Collection class superclass!
         Object class

You see, there is a sort of `parallel' hierarchy between classes and metaclasses. When you create a class, Smalltalk creates a metaclass; and just like a class describes how methods for its instances work, a metaclass describes how class methods for that same class work.

Set is an instance of the metaclass, so when you invoke the #new class method, you can also say you are invoking an instance method implemented by Set class. Simply put, class methods are a lie: they're simply instance methods that are understood by instances of metaclasses.

Now you would expect that Object class superclass answers nil class, that is UndefinedObject. Yet you saw that #new is not implemented there... let's try it:

         st> ^Object class superclass!

Uh?!? Try to read it aloud: the Object class class inherits from the Class class. Class is the abstract superclass of all metaclasses, and provides the logic that allows you to create classes in the image. But it is not the termination point:

         st> ^Class superclass!
         st> ^ClassDescription superclass!
         st> ^Behavior superclass!

Class is a subclass of other classes. ClassDescription is abstract; Behavior is concrete but lacks the methods and state that allow classes to have named instance variables, class comments and more. Its instances are called light-weight classes because they don't have separate metaclasses, instead they all share Behavior itself as their metaclass.

Evaluating Behavior superclass we have worked our way up to class Object again: Object is the superclass of all instances as well as all metaclasses. This complicated system is extremely powerful, and allows you to do very interesting things that you probably did without thinking about it—for example, using methods such as #error: or #shouldNotImplement in class methods.

Now, one final question and one final step: what are metaclasses instances of? The question makes sense: if everything has a class, should not metaclasses have one?

Evaluate the following:

         st> meta := Set class
         st> 0 to: 4 do: [ :i |
         st>     i timesRepeat: [ Transcript space ]
         st>     meta printNl
         st>     meta := meta class
         st> ]
         Set class
           Metaclass class
             Metaclass class

If you send #class repeatedly, it seems that you end up in a loop made of class Metaclass1 and its own metaclass, Metaclass class. It looks like class Metaclass is an instance of an instance of itself.

To understand the role of Metaclass, it can be useful to know that the class creation is implemented there. Think about it.

The circle is closed. In the end, this mechanism implements a clean, elegant and (with some contemplation) understandable facility for self-definition of classes. In other words, it is what allows classes to talk about themselves, posing the foundation for the creation of browsers.


[1] Which turns out to be another subclass of ClassDescription.