David Chisnall takes a look at the two dominant paradigms in object-oriented languages (classes and prototypes) and discusses the strengths and weaknesses of each.



Two terms are quite often confused when describing programming languages: class-based and object-oriented:

Simula was the first class-based language. It provided classes (actually implemented using closures) as a means of encapsulating abstract data types.

It provided classes (actually implemented using closures) as a means of encapsulating abstract data types. Smalltalk was the first object-oriented language. It provided a mechanism for decomposing programs into subprograms that ran on a simplified model of a computer and communicated with each other via message-passing.

The confusion comes from the fact that Smalltalk was also a class-based language. Most of the members of the Smalltalk family, such as Objective-C and Java, were also class-based. Some, however, were not. The first example of a language that was object-oriented, but not class-based, is Self; the most famous example is JavaScript. These languages use the prototype-based model. In this article, we'll take a look at how the two models differ, and how either can be represented in the other.

Classes and Delegates

A very common pattern in object-oriented languages is the idea of delegation. An object uses another to provide some of its functionality. This pattern is especially common in user interfaces, as a mechanism for combining the generic behavior of a view with some specific behavior for the program.

In class-based languages, subclassing is a special case of delegation. Each class has some number of superclasses to which it delegates. When you request some functionality from a class, it either implements that functionality itself, or it delegates the functionality t to a superclass. This design is extended further by objects, which are instances of classes, and therefore delegate most of their operations to a class. In a language like Smalltalk or Java, instances just contain datathey use their class delegate to provide all method implementations.

This level of delegation creates the only really confusing thing in the Smalltalk system: the metaclass. In Smalltalk, everything is an object, including classes. Objects are instances of classes; therefore, classes are instances of metaclasses. For consistency, the metaclasses must be instances of metametaclasses, which should be instances of metametametaclasses, and so on. To avoid this infinite recursion, metaclasses are actually also instances of classes. This same model exists in Objective-C, by the way, but is only exposed when you interact with the runtime library directly.

The existence of both kinds of delegation makes the delegation chain quite complex. Every message is delegated to the object's class and then delegated up the superclass chain. Messages are never delegated along the metaclass chain, except for the initial delegation.

In a prototype-based system, every object has its own methods, and delegates to its prototype. This is very simpleyou have only one kind of delegation chain, not one and a half. In JavaScript, every object has either zero prototypes or one prototype. In Self, an object can have an arbitrary number of parents, allowing the equivalent of multiple inheritance.