prototype based vs. class based inheritance
In Python, C++, etc.. there are classes, and instances, as separate concepts. In order to do inheritance, you have to use the base class to create a new class, which can then be used to produce derived instances.
There are about a hundred terminology issues here, mostly built around someone (not you) trying to make their idea sound like The Best.
All object oriented languages need to be able to deal with several concepts:
- encapsulation of data along with associated operations on the data, variously known as data members and member functions, or as data and methods, among other things.
- inheritance, the ability to say that these objects are just like that other set of objects EXCEPT for these changes
- polymorphism (“many shapes”) in which an object decides for itself what methods are to be run, so that you can depend on the language to route your requests correctly.
Now, as far as comparison:
Later OO languages wanted to be able to use static type checking, so we got the notion of a fixed class set at compile time. In the open-class version, you had more flexibility; in the newer version, you had the ability to check some kinds of correctness at the compiler that would otherwise have required testing.
In a “class-based” language, that copying happens at compile time. In a prototype language, the operations are stored in the prototype data structure, which is copied and modified at run time. Abstractly, though, a class is still the equivalence class of all objects that share the same state space and methods. When you add a method to the prototype, you’re effectively making an element of a new equivalence class.
Now, why do that? primarily because it makes for a simple, logical, elegant mechanism at run time. now, to create a new object, or to create a new class, you simply have to perform a deep copy, copying all the data and the prototype data structure. You get inheritance and polymorphism more or less for free then: method lookup always consists of asking a dictionary for a method implementation by name.
A comparison, that is slightly biased towards the prototypes based approach, could be found in the paper – Self: The power of simplicity. The paper makes the following arguments in favor of prototypes:
Creation by copying. Creating new objects from prototypes is accomplished by
a simple operation, copying, with a simple biological metaphor, cloning. Creating
new objects from classes is accomplished by instantiation, which includes the
interpretation of format information in a class. Instantiation is
similar to building a house from a plan. Copying appeals to us as a simpler metaphor
Examples of preexisting modules. Prototypes are more concrete than classes
because they are examples of objects rather than descriptions of format and initialization.
These examples may help users to reuse modules by making them easier to
understand. A prototype-based system allows the user to examine a typical representative
rather than requiring him to make sense out of its description.
Support for one-of-a-kind objects. Self provides a framework that can easily
include one-of-a-kind objects with their own behavior. Since each object has
named slots, and slots can hold state or behavior, any object can have unique slots
or behavior. Class-based systems are designed for situations where
there are many objects with the same behavior. There is no linguistic support for an
object to possess its own unique behavior, and it is awkward (think Singleton pattern) to create a class that is guaranteed to have only one instance. Self suffers from neither of these disadvantages.
Any object can be customized with its own behavior. A unique object can
hold the unique behavior, and a separate “instance” is not needed.
Elimination of meta-regress. No object in a class-based system can be self-sufficient;
another object (its class) is needed to express its structure and behavior.
This leads to a conceptually infinite meta-regress: a
point is an instance of class
Point, which is an instance of metaclass
Point, which is an instance of metametaclass
Point, ad infinitum. On the other hand, in prototype-based systems an object
can include its own behavior; no other object is needed to breathe life into it. Prototypes
Self is probably the first language to implement prototypes. (It also pioneered other interesting technologies like JIT, which later made its way to the JVM. So reading the other Self papers should also be instructive).
- Suitable in loosely typed environments, no need to define explicit types.
- Provides ways of applying a method of an object in the context of a different object, adding and replacing methods dynamically from an object etc. (things which are not possible in a strongly typed languages).
Here are some of the cons of prototypal OO:
- No easy way of implementing private variables. Its possible to implement private vars using Crockford‘s wizardry using closures, but its definitely not as trivial as using private variables in say Java or C#.