- Classes and Delegates
- Differential Inheritance
- Hidden Class Transforms
- Models and Views
Differential Inheritance
In a class-based language, everything about an object is defined by its class, which defines the state that the object stores, as well as its possible interactions. You typically can't add instance variables (state) to an object in a class-based language if they're not declared in the class (or a superclass).
A prototype-based language removes this special treatment of classes. Any object can be extended in exactly the same way as a class, adding new properties as well as new methods.
The thing that often trips up people moving from class-based languages to prototype-based languages is the lack of distinction between methods and instance variables in a typical prototype-based language. When you send a message to a Smalltalk object, the object's class is used to look up the method. When you access an instance variable, it's loaded from some fixed offset from the start of the object (or, in some cases, from a linked list at the end).
In Self-like languages, both of these possibilities are handled by the slot mechanism. Objects have a collection of slots, indexed by string values. Rather than storing state at some fixed offset from the object's start, the state is stored in this dictionary. This approach is necessary because Self-style objects don't have a fixed layout determined by their class.
The same mechanism is used for method lookups. In fact, Self and JavaScript don't have methods as a language conceptthey have closures stored in slots. When you call a method, you're really just invoking a closure that has been stored in a slot on an object.
Because (the equivalent of) both methods and instance variables are stored using the slot mechanism, they're subject to the same inheritance pattern. This pattern is called differential inheritanceonly the differences between an object and its prototype are stored.
This design lets you do some very interesting things, but it can also cause some confusion. It's important to remember that a clone is not the same as a copyslot lookup uses the same delegation/inheritance mechanism as method lookup in a class-based language. For example, if you create an object with a count field and then clone it, inspecting the count field in either the original object or the clone will give you the same slot. If you modify the value in the original, the change is visible in both. If you modify the clone, the new value is visible only in the clone. This is because lookup happens in the same way that method lookup happens with classes: If you override a method in a subclass, that method is visible only in the subclass. If you replace the method in the superclass, that change is visible in all subclasses that don't override the method.