** 19. Classes, Metaclasses, and Prototype-Based Languages ** ---------------------------------------------------------------------------- 19.1. Some basic language design principles of standard OO languages: 1) every object has a class *) the class holds the methods & inst var declarations for the object *) the object holds the inst var contents *) when the object receives a message, it asks its class for the right method to invoke *) inheritance is between classes 2) everything is first-class *) first-class things are objects in OO languages *) classes are things => classes are objects Why should classes be first-class? So that they can be passed around the program like regular values, and then their operations invoked. What methods might be on classes? Constructors, and methods & data that are "static" in Java. E.g., you can compute the class of objects to create (called factories in the design-patterns (and earlier) literature). Hard to argue with these two principles. But, wow, the implications: 1 + 2 => a class has a class. The class of a class is called a metaclass. What does it do? *) the metaclass stores the methods and inst var declarations for the class (when the class is treated as an object) *) the class holds the inst var contents of its inst vars *) when the class object receives a message, it asks the metaclass for the right method to invoke *) inheritance of these class methods is between metaclasses ---------------------------------------------------------------------------- 19.2. Metaclass designs: Metaclasses are classes, which are objects, which have classes. What is the class of a metaclass? .... infinite regress .... Infinite regress solutions: Smalltalk-76: The class of all class objects is the Metaclass class object. This implies that it is its own class, circularly. *) fairly simple solution *) since there's only one metaclass, all classes must have the same methods (e.g. all the same constructors) & instance variable declarations => pretty limiting Smalltalk-80: Each class in the ST-76 picture is actually a pair of classes: a regular class, and its metaclass. The class of each class's class is the Metaclass class, which has its own internal class, which has Metaclass as its class, circularly. *) since each class has its own class, each class can have its own methods and instance variables *) very complicated Other solutions: change one of the basic design principles Option 1: make classes second-class (e.g. C++) *) Classes aren't objects, cannot send messages to them, no need for metaclasses Option 2: a blend of C++ and ST-76 (e.g. Java) *) Classes are objects, instances of class java.lang.Class, which is an instance of itself (I suppose!) *) To allow individual classes to have their own operations, constructors and static methods & instance variables are allowed per-class, but these aren't treated as operations on class objects, but of a second-class nature. So the ability to pass around class objects and thereby compute the class to instantiate is lost (aside from the one newInstance method defined on all class objects). Option 3: drop classes altogether, leading to prototype-based languages... ---------------------------------------------------------------------------- 19.3. Prototype-based OO languages: Basic difference from class-based languages: an object has no need of a class, but instead (logically) stores its own methods, instance variable declarations, and inheritance from other objects. The syntax of class declarations can be changed only slightly to declare an object directly, in a manner akin to how the objects-as-records encoding has objects just be created directly from records containing data and functions. New objects can also be created by cloning (i.e. copying) existing objects, which is akin to instantiating a class, but using an existing object as the pattern rather than some more abstract description in a class. One object can inherit from another object directly, meaning that it shares its methods and instance variable state, if not locally overridden. New instances can also be defined by inheriting from existing objects rather than cloning them. If factory objects are desired, they can be programmed explicitly, as regular objects, without needing to build in a class construct. Self is the most well-known prototype-based language. Cecil is also classless, although not as much as Self, since one can only inherit from a statically declared object, not a run-time computed object. The former is closer to class-based programming, and easier to statically type-check and compile, but still does not require the language semantics to be cluttered with classes or metaclasses.