CSC/ECE 517 Fall 2010/ch7 4e ak: Difference between revisions
Line 53: | Line 53: | ||
Note that both features may not be supported by all prototype-based languages. One notable example is 'Kevo' which supports only cloning and adding new properties to clones. The main difference between the two lies in the way objects share their properties. This is because cloning employs 'shallow cloning/copying'(see wikipedia). In other words, the values of the properties are copied and they don't share any references with each other. As a result, cloned objects tend to evolve in a direction independent of their source. | Note that both features may not be supported by all prototype-based languages. One notable example is 'Kevo' which supports only cloning and adding new properties to clones. The main difference between the two lies in the way objects share their properties. This is because cloning employs 'shallow cloning/copying'(see wikipedia). In other words, the values of the properties are copied and they don't share any references with each other. As a result, cloned objects tend to evolve in a direction independent of their source. | ||
:: For example: | :: For example: | ||
[[Image:traits.png]] | |||
In the above image, even though ''ClonedPerson'' was derived from ''OriginalPerson'', the OriginalPerson's name did not change even after we changed the 'Name' property of ClonedPerson to 'Clone1'. So they are not connected in anyway. | |||
But in the case of objects created by 'extension', they tend to share the same references. So, whenever the value referred to is changed via either of the objects, the change is visible to all the instances. Also when extending, properties are not copied. Rather they are delegated. Delegation is a very important feature of prototype based programming. | But in the case of objects created by 'extension', they tend to share the same references. So, whenever the value referred to is changed via either of the objects, the change is visible to all the instances. Also when extending, properties are not copied. Rather they are delegated. Delegation is a very important feature of prototype based programming. | ||
Revision as of 04:01, 2 December 2010
Prototype-based programming - Introduction
What is prototype based programming
Prototype based programming is a family of languages supporting object oriented development based on the concept of 'prototype', rather than a 'class' in languages such as Java, C++ and C#. In otherwords, these languages propose a new world in which there are no classes and behavior reuse is done via cloning/extending objects which are already present. Also known as 'class-less' or 'instance-based programming', some of well-known languages belonging to this category include Self, JavaScript/ECMAScript, NewtonScript, Lua.
Flashback
It all started with frame theory and frame-based languages such as KRL and FRL. These languages allow us to capture knowledge such as default values or exceptions. A frame is a set of attributes each mapped to a set of facets(usually a single value). We will see how this influenced prototype based languages through the course of this article. One of the most popular prototype-language 'Self' was developed by David Ungar and Randall Smith when working at Sun microsystems throughout 1980s and 90s. The self project aimed at providing near 'C' performance via JIT compilation techniques and runtime optimizations. Infact, some of these optimizations are implemented in JVM.
WHAT WILL BE COVERED?
Goals
Simplicity
One of the basic tenants of prototype based programming languages is that: 'Avoid classes. They are just too hard' Why so? Well, we humans tend to grasp new concepts only by working with concrete examples rather than with abstract descriptions. For example, when learning math, we tend to work out a large number of examples before deriving relationships and equations. Classes are similar to equations. They are abstractions of the concrete objects we are trying to model. They force us to think in the opposite direction and hence tend to be counter productive in a number of situations. No wonder its so hard to design classes and their responsibilities. We never get it right the first time. ;)
Reduce concepts/provide lesser primitives
If you have done GUI programming using Java's Swing or GTK+, then you know classes don't make it any easier to program. Sometimes, these classes tend to play a very large number of roles and it is hard to reduce complexity in such scenarios. Prototype-based languages tend to move away from classes and provide protoypes which can be very easily customized/extended.
Extensibility/Dynamic behavior
Protoype-based languages are inherently dynamic. Languages in this family allow new methods/attributes to be added/removed in the prototype at runtime.
Some of the prototype-based languages have evolved and include quasi concepts from other language families. This could be attributed to design constraints, improve performance etc.. Likewise, some of the concepts of prototype-based languages have been adopted by a number of languages.
Concepts of creation and representation
As mentioned earlier, prototype based programming allow us to create new objects, modify their behavior in any possible manner.
Creation
Creation of objects can be classified into two types.
- Ex nihilo
- Extending an already existing prototype
Ex nihilo
This is a type of object creation in which the object is created ex nihilo. In otherwords, it is derived from no object. For example, in JavaScript, to create a new object Person with attributes name, age:
var Person = { name: 'Kovalan', age: 23 }
Note that, the above object was created from nothing, simply by using '{}' braces.
Extending an already existing one
Here, we create a new object by extending/cloning an already existing object/prototype. For example in Javascript,
//source: StackOverflow. function extend(o) { function F() {} F.prototype = o; return new F(); } var newObject = extend(Person);
Actually there are two concrete types of creating objects based on a prototype.
- Cloning
- Extending
Note that both features may not be supported by all prototype-based languages. One notable example is 'Kevo' which supports only cloning and adding new properties to clones. The main difference between the two lies in the way objects share their properties. This is because cloning employs 'shallow cloning/copying'(see wikipedia). In other words, the values of the properties are copied and they don't share any references with each other. As a result, cloned objects tend to evolve in a direction independent of their source.
- For example:
In the above image, even though ClonedPerson was derived from OriginalPerson, the OriginalPerson's name did not change even after we changed the 'Name' property of ClonedPerson to 'Clone1'. So they are not connected in anyway. But in the case of objects created by 'extension', they tend to share the same references. So, whenever the value referred to is changed via either of the objects, the change is visible to all the instances. Also when extending, properties are not copied. Rather they are delegated. Delegation is a very important feature of prototype based programming.
//SHOULD WE DESCRIBE DELEGATION HERE?
Modification
Prototype based programming allows us to modify objects in a number of ways including the following:
Add/Remove new attributes to an object/prototype
For example, in JavaScript
var Person = {name: 'John' }
to add a new property 'age' to person,
Person.age = 23
and to delete the property age, its as simple as:
delete Person.age
Change the value of an attribute
For example assume,
Person = {name: 'Abcd', age: 99 }
To change age to 23, we write.
Person.age = 23
Add/Remove methods to/from an object/prototype
For example, to add a new method to Array prototype in js, we write:
Array.prototype.isEmpty = function(){ return this.size() == 0; }
to delete the method 'useless' from Array prototype(assuming we added it earlier),
delete Array.prototype.useless
The whole world of objects is open for modification and extensibility. This is very similar to how other dynamic programming languages like python, ruby operate. However, deleting/modifying standard methods are frowned upon.
Concepts of representations
Objects compose two types of primitives:
- Properties/Variables: these are simple variable types(such as 'string', 'array' etc..)
- Methods: responsible for behavior/characteristic of a prototype. methods/functions operate on properties and respond to requests/invocations.
The above concept is the same in almost all the languages such as C++, Java, Ruby, Python etc... However, in prototype based languages there are two broad concept of representations.
- Slots: Everything including a property/method is a slot. Slots are placeholders which respond to messages. For example, a property is a slot which when invoked with nothing yields its value. If invoked with a value, the property stores this value. Likewise, a method also responds to messages.
- Keep them separate: Properties and methods are treated separately(as in languages like Java, C++). Self introduced the concept of a 'trait'. Trait objects are repositories of methods/functions. These apply to a whole family of objects and so its logical to keep the properties and methods separate. So, when viewing objects inheriting from a parent object, all the values(concrete objects) tend to be stored in the leaf nodes.
In the above image, both print and println are methods in the trait and the objects ConsoleWriter and FileWriter make use of those methods. Only the property out changes.
Languages
JavaScript
One of the most popular prototype languages, it was developed by Brendan Eich when working for Netscape. It is the standard programming language supported by all the web browsers(including Firefox, Google Chrome, Opera). There are a number of JavaScript frameworks out there to simplify the development of prototypes in js. jQuery, PrototypeJS, Moo-tools are some of the popular ones.
Self
It was designed by David Ungar and Randall Smith in 1986 while working at Xerox. Later they moved to Sun Microsystems where, it is still under continuous development. It supports garbage collection(like Java) and several JIT techniques were pioneered in Self research. Some of these techniques are currently implemented in JVM.
Lua
One of the relatively new programming languages emerging out of Brazil, it was created in 1993 and is now very popularly used as a scripting language in game engines used on ipad/iphone/etc.. However, it is not a pure prototype-based language; rather a number of programming paradigms are incorporated.
Drawbacks
Even though prototype based languages are highly flexible and dynamic, they do not provide type safety or predictability. With class-based programming languages, it is easier to predict the outcome of programs given the static nature of the classes and hence prove correctness. Another concern is that of efficiency of prototype-based languages. Classes being static in nature allow the compiler to perform a large number of optimizations which are not currently possible with prototype-based languages. Having said that, currently there is a very healthy competition among different browser vendors such as Google, Microsoft, Firefox/Mozilla, Opera to provide the fastest javascript execution engine. In otherwords, a number of new techniques are still being pioneered to improve the performance of prototype based languages.
Conclusion
Thus all the prototype based languages incorporate the concept of 'prototype' and creating/deriving new objects from this prototype. This line of thinking has inspired a number of beautiful languages including JavaScript, Lua, Self and much more.