CSC/ECE 517 Fall 2010/ch4 4e ms
Prototype Based Programming
"Objects in the real world have only one thing in common: they are all different" (anonymous, A. Taivalsaari, JOOP, Nov. 1997)
Introduction
Prototype based programming is an object oriented programming methodology. It differs from the other classes of object oriented languages due to its main characteristic feature that no classes are present in the language constructs. Behavior reuse or inheritance function is performed by cloning some prototype objects. It is thus also known as instance-based programming or class-less based programming and such languages are known as prototype based languages.
Objects used in prototype based programming are referred as prototypes, which resemble an instance of class in class-based programming. It differs from a class instance as one can add or remove variables and methods at any level of a single object, without worrying if the object still fits in the system. Typically, new objects are created by copying existing objects, which is called as cloning.
The figure below shows where prototype based languages fit in the broad classification of object oriented languages.
History
- Eleanor Rosch first introduced the 'Prototype Theory' in mid-1970's. Rosch proposed that to classify objects, one can match them against a "prototype" i.e. an ideal example which exhibits the most representative features of the category of objects. This evolved the concept of frame based languages that used the prototype theory in the field of knowledge representation languages. Here, frames were used to represent knowledge like typical values, default values, or exceptions.
- The concept of prototypes was later picked up in programming languages in the 1980s when Borning proposed the description of a classless language. The underlying feature of this language was that new objects were essentially being produced by copying and modifying prototypes. The classless model of object oriented programming thus brought forward several issues related to class based programming and proposed various solutions based on the use of prototypes. [1]
Characteristics
In prototype based languages, prototype is chosen by using concrete examples rather than abstracting out common attributes. This offers a programming model with fewer primitives. This is also a less restrictive knowledge representation model wherein objects are not coupled too tightly. Most popular object-oriented programming languages used are class based where all objects of a certain class share the same properties. At first the prototype paradigm is difficult to comprehend compared to class-based, such as Java and C++, which base their structure on the concept of two marked entities: classes and instances. We comparatively discuss the features of prototype based languages with class-based ones to understand its programming model.
Comparison between prototype-based languages and class-based languages
Feature | Class Based Programming e.g. Java, C# | Prototype-Based Programming e.g. JavaScript, Self |
---|---|---|
Object Model | Based on the class and instance entity model i.e. structure of object is defined by classes. | Every object is an instance, there are no classes. |
Object definition and creation | Class defined with explicit class definition; class instantiated with help of constructors. | Creates objects by assigning an object as the prototype where each prototype is associated with a constructor function. |
Abstraction | Uses abstract definitions/representation. | Does not use abstract definitions. |
Parental Dependency | The parent of an object cannot be altered | Allows to change parent of object at runtime |
Inheritance | Class definitions are used to define subclasses and the subclasses inherit properties by following the class chain. | Objects inherit properties based on the hierarchy of the prototype chain. |
Dynamic Structure | The class structure is static and contains all the properties that an instances of a class can have. One cannot add properties dynamically at run time. | The prototype or constructor function specifies the initial set of properties and one can add or remove properties dynamically of the particular object or of the entire set of objects. |
Thus, prototype based languages offer capabilities to represent knowledge in a way different than class based languages. Some of these representations are sometimes difficult to represent in class based languages. e.g. 1. one can have different objects of the same family but having different structures and behaviors e.g. 2. objects with totally exceptional behavior e.g. 3. objects with viewpoints and sharing at the object level e.g. 4. incomplete state objects
Also, in the real world entities or objects can be viewed as sets or prototypes. Sometimes modeling these architectural features in class-based languages exhibits certain limitations as they are rigid in terms of defining concepts with the idea of shared properties. Some real world examples where prototype based appraoch is preferred to class based one are traffic jam representation systems, greenhouse effect representation systems.
Reference: https://developer.mozilla.org/en/JavaScript/Guide/Details_of_the_Object_Model
Classification of Prototype Based Languages
It is very challenging to classify the set of prototype based languages due to the variations in implementation models for each language. However, these are needed at some level to adjudge which programming language model best suits the given needs.
At a very abstract level there are 2 major classifications:
1. Based on Primitive Semantics
2. Based on Group Oriented Constructions.
Primitive Semantics
- Slots or methods and variables
A property is a binding of a name to a value within an object and each object is defined by a set of properties. Properties can be of two kinds: attributes or methods. In general programming terminology one can represent these properties of objects in two ways: 1. By separating attributes and methods . 2. By amalgamating attributes and methods into something known as "slots".
Thus, slots hold data values as well as methods. Some languages differentiate between methods and variables, while others treat them in the same way. Self treats methods and variables as same, which allows to over-ride an attribute with a method and vice versa. In prototype based languages one can add or change not only data but also methods. For this reason, most prototype-based languages refer to both data and methods as "slots". Slots are defined to answer messages. Either data or code can be found in a slot as the result of sending a message. Data is just returned, and code is actually executed. If a prototype does not contain a requested slot or does not know how to answer a specific message it may delegate the request to another prototype through an inheritance relation which is discussed next.
- Object Creation
Objects can be created in two ways:
1. Ex nihilo (from scratch)
2. From existing object (by cloning or extending)
- Inheritance and Sharing
Since the prototype is used to create other objects using cloning, its properties can be read through all objects of the class. These properties are actually a single shared copy. Thus a read on these properties will retrieve the shared value from the prototype object. The cloned object can then either set the value of one of these properties. This action will actually create a new property for that object. This new property can then 'shadow' or 'hide' the property from prototype object. Following diagram illustrates how the shared prototype property is shadowed by the private object property. Clones in some languages don't get affected by change in their parent's behavior, thus help an object to not unexpectedly change through its clone.
>>>>>>>>>>>>>>> DIAGRAM
Languages are classified on the basis of how the primitives of writing on shared property, creating new property, message passing affect the prototypes e.g. Javascript and Kevo both handle object sharing differently
http://docstore.mik.ua/orelly/web/jscript/ch07_04.html
- Delegation:
Delegation is a language feature that ‘delegates’ or ‘hands over’ a task to another object based on certain method lookups in the hierarchy at runtime. Thus, an object can use another object's behavior. This sounds a lot like inheritance, but inheritance allows the similar method dispatching based on the ‘type’ of object at compile time as opposed to delegation which works on instances. Thus, delegation be used to support inheritance of methods in a prototype based system.
Delegation is of two types:
Value Sharing: A type of sharing between representation of different entities. It is the ability of an object to share the values of a parent when an object is made using clone.
Property Sharing: A type of sharing between viewpoints on the same entity. It is the ability of an object to share all or some of its properties with another object.
- Primitives of virtual machine: The semantics of the virtual machine primitives underlying each language also distinguishes the various types of programming languages.
Group Oriented Constructions
This is a classification according to the level of abstractness of the constructions.
- Purely prototype based: Self, Kevo, Taivalsaari, Agora, Garnetk **Moostrap, Omega, Obliq, NewtonScript
- Not Strictly prototype based: Object-Lisp, Yafool
- Languages mixing prototypes and classes.
Programming Constructs
Prototype based languages are varied in terms of their implementation patterns. We will consider the features of JavaScript, one of the most popular prototype based languages, for deeper insight into the typical implementation of programming constructs in prototyping.
Creating Objects
As mentioned earlier the object property can be either methods or attributes. While creating a new custom the constructor function is used which typically wraps the initial values to properties of the object. e.g.
Function car(plate, model, color) { this.plate = plate this.model = model this.color = color } var car1 = new car("AB 123", "Ford", "blue")
Javascript makes use of the new keyword.
On creation the new object will have the properties as:
car1.plate //value="AB 123" car1.model //value="Ford" car1.color //value="blue"
In prototype based languages one can add own customized properties to any object. For this no special declarations are needed, just choosing the name of property and accessing it takes care of the inclusion of the property.
We can illustrate this with above example. Consider we add a new property to the constructor's prototype property like shown below-
car.prototype.companyOwned = true
This will then affect any new object that we are about to create as it automatically inherits the new property and its value. However, one can still override the value of the companyOwned property for an individual car object. There are different variations to this rule and different programming languages can restrict this kind of change propagation.
Cloning
There are 2 levels at which an object can be cloned. These are deep and shallow cloning. In shallow cloning, a copy of an object is created wherein just the references of the sub-objects are copied. In deep cloning, a complete duplicate of the original is created, i.e. it creates not only the primitive values of the original object but also copies all its sub objects as well.
JavaScript supports both shallow and deep cloning. The copy(), clone() and deepCopy() functions are used to clone a object. i) clone() uses JavaScript's built-in prototype mechanism to create a cheap, shallow copy of a single Object.
e.g. john2 = owl.clone(john);
ii) copy() makes a shallow, non-recursive copy of a single object.
e.g. john4 = owl.copy(john);
iii) deepCopy() is the entry point for the deep copy algorithm. Every member is recursively deep copied:
e.g. john4 = owl.deepCopy(john);
>>>>>>>>>>>>>>Diagram
Delegation
Instead of adhering to class, subclass and inheritance schemes similar to object oriented languages like Java, Javascript has prototype inheritance. Suppose the script wants to read or write a property of an object then following sequence search is performed over the property name:
- prototype property of instance is picked if defined
- if no local value check value of prototype property in object’s constructor
- continue protoype chain till match found upto native Object object.
Event delegation with Javascript:
>>>>>>>>>>>>>>>>>>>>>>>>>>>>Can give a diagram here
References: http://robertnyman.com/2008/05/04/event-delegation-with-javascript/
Concatenation
Under pure prototyping, which is also referred to as concatenative prototypes, there are no visible pointers or links to the original prototype from which an object is cloned e.g Kevo.The prototype object is copied exactly, but given a different name (or reference). Behavior and attributes are simply duplicated as-is. Advantages to this approach include the fact that object authors can alter the copy without worrying about side-effects across other children of the parent. A further advantage is that the computational cost of method lookup during dispatch is drastically reduced when compared to delegation, where an exhaustive search must be made of the entire delegation chain before failure to find a method or slot can be admitted.
Disadvantages to the concatenative approach include the organizational difficulty of propagating changes through the system; if a change occurs in a prototype, it is not immediately or automatically available on its clones. However, Kevo does provide additional primitives for publishing changes across sets of objects based on their similarity (so-called family resemblances) rather than through taxonomic origin, as is typical in the delegation model. Another disadvantage is that, in the most naive implementations of this model, additional memory is wasted (versus the delegation model) on each clone for the parts that have stayed the same between prototype and clone. However, it is possible to provide concatenative behavior to the programming while sharing implementation and data behind-the-scenes; such an approach is indeed followed by Kevo.[4]
An alternative quasi-solution to the problem of clones interfering with the behavior of the parent is to provide a means whereby the potential parent is flagged as being clonable or not. In MOO, this is achieved with the "f" flag. Only objects with the "f" flag can be cloned. In practice, this leads to certain objects serving as surrogate classes; their properties are kept constant to serve as initial values for their children. These children then tend to have the "f" flag not set.
Message Passing
A message is a method call on an object. As different objects can have their own functions different functions, when invoking a function, it is necessary to make sure that the object implements that function. If a function is called on a object which does not invoke it, it throws an exception. But instead if we use message passing to invoke a function and if the object is not invoking that function, it simply returns a null.
In JavaScript,
var myCar = new Car(); var returnValue = m(myCar, ‘carColor’, 1999);
(this code is created/modified) A message will be passed to myCar object instance, which then invokes the function carColor that returns something. The return value will be sent back and and will be assigned to returnValue just like a traditional function call. If the object doesn't implement carColor, it wont throw an exception, instead the return value will be just null.
(the “alternatively” below is copied entirely) Alternatively, an object can forward the message to another object, which might implement the requested function. All it has to do is to implement a function called forwardInvocation. It can even contain some logic like instantiating a globally accessible object which contains the requested function and then forward the message to it. Let's take for an example the following MooTools classes:
var class1 = new Class({ forwardInvocation: function(){ return object2; } });
var class2 = new Class({ forwardInvocation: function(){ return object3; } });
var class3 = new Class({ receivingFunction: function(){ return 'Message received.' } });
object1 = new class1(); object2 = new class2(); object3 = new class3();
If we now run the following code:
alert(m(object1, 'receivingFunction'));
Then the message handler will recursively forward the message from object1 to object2 until it finally reaches object3, which then returns the string Message received that eventually will be displayed as an alert message (who would have guessed).
Other Prototype Based Languages
Self
Self is the canonical example of prototype based languages. Self is similar to Smalltalk in syntax and semantics. but uses prototypes, unlike Smalltalk which uses class based paradigm.
Objects: Objects are comprised of slots, the slot stores name and reference to the object. A slot contains the behavior and state of an object. Interaction with object is done with message sending. Slots can be categorized as method slots and data slots. Method slots are used to return result when a message is received, while data slots work like class variables in class based programming.
Creation of Objects: New object is created by making a copy of existing object and then adding slots to get desired behavior.
Inheritance: Data slots can be made as parent slots. A parent slot delegates message to the objects it refers, if the selector of that message is not matched to any slots in it. Thus, a method has to be written only once. When methods are written in a triat object, it can be used by any other object.
Omega
Forth
Kevo
Kevo is another prototype based programming language created by Antero Taivalsaari for Macintosh computers. It is semantically similar to the languages Self and Omega and resembles Forth syntactically. It varies from other prototype based languages in the way inheritance and delegation are handled in it. This is mainly because Kevo objects are self-contained and do not share properties with other objects i.e. it follows the concatenation model where changes in the prototype do not propagate to the cloned object. Kevo provides the extensibility to manipulate objects flexibly by use of certain module operations. These module operations are capable of publishing updates from the prototype across a certain set of objects based on their similarity in the family tree by use of some additional primitives. Another distinct feature of Kevo is that it uses a threaded code interpreter.
NewtonScript
NewtonScript was created by Walter Smith for Apple's Newton MessagePad. The motivation for creation of this language was designing GUI fro the Newton platform with low memory consumption. As this is an issue in class-based languages wherein an instantiation of a class causes memory being allocated for all object attributes, Walter chose to design a prototype based language wherein creating an instance would be equivalent to creating a frame that inherits from some prototype frame. Note that this class creation scheme does not allow data hiding, instance variables are still accessible from other functions not belonging to the class. It allows factoring out common behaviour of frames and gives some clearly defned interface to a set of data. Applications of NewtonScript are now only restricted to mainly the Newton platform mobile and embedded devices. Despite running on a platform with only 128K of RAM, NewtonScript supports many modern language features such as exceptions and garbage collection.
As a prototype-based language, NewtonScript inheritance also differs from classical object-oriented inheritance. Every frame has a "prototype," which is referenced in the "_proto" slot (slots in NewtonScript are analogous to instance variables in other languages). If you attempt to access a slot that does not exist, the frame will delegate to its prototype.
Frames may also have a "parent," referenced in the "_parent" slot. This second way of inheritance is designed to facilitate hierarchies of user interface elements; a button might have its _parent set to a toolbar, which would then have a _parent of the main view.
In an object-oriented language, making objects like buttons with different behaviors is a tedious ordeal. Either every kind of UI widget needs a different class, or each widget ends up delegating to a huge controller object, existing solely to perform UI actions. NewtonScript avoids this problem by removing classes altogether; just set the ButtonClickScript of your button to whatever function you need, or change the viewBounds slot to the new dimensions of your widget.
NewtonScript uses an inheritance scheme which is derived from SELF. SELF's inheritance mechanism is very flexible. For the special purpose of writing GUI application, NewtonScript has a simplified double inheritance scheme. The two ways of inheritance are very much fixed in purpose when implementing windows and dialog controls, but can be used more generally as well.
3.1 Prototype inheritance
First, each frame can have a prototype frame from which it is derived. The mechanism is rather simple, the frame contains a slot called _proto and each time the NewtonScript interpreter does not find a slot variable or function locally it looks into the frame's prototype and then recursively into its prototype until the whole inheritance chain was searched through. When a new slot variable is created that already exists in a prototype a new slot variable is created in the current frame. During lookup this new variable is found first and semantically replaces the prototype variable. From a conventional viewpoint prototypes serve two roles. First, they are the equivalent to user-defined types, to create an instance of the type, you just have to create an object derived from the object that defines the behavior of your type. Second, prototypes provide the class inheritance mechanism of class based languages.
The dialog creation mechanism of NewtonScript uses prototype inheritance extensively to create dialog items. When a new instance of a built-in dialog element is created the new instance has the built-in object as its prototype. This object created by the user is then called a template in NewtonScript terminology. When this object is then actually put onto the screen, the system itself creates another object having the template as prototype, with some redefined slots to designate view boundaries for example. Thus the template can be reused to create more dialog controls with similar properties. 3.2 Parent inheritance The second way of inheritance is conceptually quite similar to prototype inheritance, besides the _proto slot a slot called _parent points to another inheritance chain similar to the prototype chain. This second inheritance scheme is again made to fit into the GUI design, all child-windows have a child-parent inheritance relationship to their parent windows. An application normally consists of a parent window, which is in turn child of the system's root window. All windows and dialog controls are then hierarchically ordered below this application parent window. Parent inheritance has an effect similar to prototype inheritance, variables not found neither in the frame itself nor in its prototypes are searched for in the parent frames and their prototypes and so forth. Thus slots in the parent window of an application serve as application wide globals. Assignment rules are a little different from the prototype inheritance rules, you can assign values to slots which reside in your chain of parents and grandparents as you can assign values to global variables in other languages without replicating these variables locally in the current frame.
For function lookup, NewtonScript only searches the prototype chain, not the parent chain, although a frame can call a function in one of its parents directly by dereferencing its _parent slot. It does not become entirely clear why this is so, I think it is more because of practicality than principle.
Reference: http://www.grin.com/e-book/96313/the-newton-script-programming-language
Disadvantages/Criticism
- Unlike prototypes, classes provide a contractual guarantee to their objects and to their users to about their behavior. Concerns involving safety and predictability are better handled by classes. Example: Delegation allows an object to change its parent during runtime. If ill-planed changes are made using delegation, the program will behave unpredictable.
- Efficiency of language-compiler reduces when prototypes are used. These languages don't allow developing efficient methods and instance variable lookups.
- The community of software developers in present day is unfamiliar with the concept of prototypes and languages based on them.
Applications
Most of the prototype based languages were developed as needs to certain specific applications. These applications include: 1. Low memory consumption based systems e.g. NewtonScript 2. Vocabulary acquisition and teaching analysis 3. Mental lexicon analysis 4. Cognitive linguistics and linguistic data analysis
Referece: http://www.directessays.com/viewpaper/78763.html]
Conclusion
Thus prototype based languages propose a vision of object-oriented programming based on the notion of a prototype. Numerous prototype based languages have been designed and implemented. Most popular ones include Self, Kevo, Agora, Garnet, GlyphicScript, Moostrap, Omega, Obliq and NewtonScript. Some languages like Object-Lisp and Yafool which are not strictly prototyped but offer related mechanisms by use of prototyping at the implementation level have also been developed. All of these represent another view of the real world objects not relying on advance categorization and classification, but rather on making the concepts in the problem domain as tangible and intuitive as possible.
Suggested Reading/See Also
External Links 1. Prototype design pattern - influenced by prototype programming paradigms 2. http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.123.9056&rep=rep1&type=pdf Internal Links
References
Papers:
- Borning A (1986), Classes versus Prototypes in Object-Oriented Languages, IEEE Computer Society Press, In Proceedings of the IEEE/ACM Fall Joint Conference.
Books:
- Marcus Arnstrom, Mikael Christiansen, Daniel Sehlberg Prototype-based programming (May 2003).
Prototype Based Programming - Concepts, Languages and Applications By James Noble, Antero Taivalsaari, Ivan Moore
Links: