How-to: Prototype Oriented Programming in JavaScript
March 27th, 2009
JavaScript is now the world most popular programming language. And I must agree with Douglas Crockford - also the world most misunderstood programming language.
JavaScript was developed on a solid programming paradigm, and is a very flexible and powerful language. Still, until the RIAs came into scene, it was though to be a helper language with little or no use. And its powerful prototype orientation was held as another reason to diminish it: most programmers distrust its flexibility.
However, RIAs, Ajax and now jQuery appeared, and now we’re talking about JavaScript. jQuery makes intensive use of JavaScript’s prototype orientation, and is one of the key reasons of jQuery’s great success.
I’ll explain now how to fully implement prototype orientation in JavaScript. For space reasons, patterns and best practices will be posted later.
Applying prototype orientation in JavaScript
Every JavaScript object has a member called prototype. Making the method call new FunctionName() will result in a replica of FunctionName.prototype. When using classical style inheritance and objects in JavaScript, we first create a function called FunctionName that will serve as the constructor, and then we add member methods and member objects to the FunctionName.prototype . We can add members to FunctionName outside the prototype, and they won’t be copied into the instances. So, FunctionName behaves almost like a class.
In prototype orientation objects clone from objects. So, for prototype orientation to work in JavaScript we need two things:
- Some way to aggregate objects from the ground, without a class or class-like function
- The ability to clone objects
We have both: JSON, and a snippet of nifty Crockford’s code. Let me explain it further:
Aggregating Objects
An object seen as an aggregate is outstandingly descript in JSON. JSON is a lightweight object serialization language (JavaScript Object Notation) developed by Douglas Crockford, and implemented in mayor browsers several years ago. This is not the place for an extensive explain about JSON, but let me show you some samples of JSON code, applying the Garden prototype as described in my last article:
var Garden = { “road”: “grey”, “flower”: “rose”, “floor”: “grass”, “animal”: “bird” }
This is the static way of object generation in JavaScript. There is also a more dynamic, for method and member adding and deleting, anytime, anywhere:
Garden.sky = “blue”; // Adds the member sky, and set’s it as blue Garden.watch = function () { // Adds the method watch to the Garden alert(”A ” + this.road + ” road, a ” + this.flower + “, a ” + this.animal + “, dude, this is beautiful!”); }
Cloning objects
Now, we want to create a Garden for our house. Let’s say
var myHome = { “garden”: null // garden initialized in null, since we have not a garden cloning ability yet }
We could have defined Garden as a function. In JavaScript, all functions have a member called prototype, that is instantiated every time we make the call new FunctionName();. But this would force us to keep functions working as classes, and still we can’t clone an object we already have.
So, let’s make a twist about it (all credits to Douglas Crockford):
// o is the name of the object to be cloned function object(o) { function N() {} // We define a new, empty function. N.prototype = o; // The prototype of N is now the object we want to clone. return new N(); // Since N.prototype is o, our object-to-be-cloned, a clone of o is returned }
And that’s it! Fabulous. We can now have our precious garden, and, of course, watch it:
myHouse.garden = object(Garden); myHouse.garden.watch();
Copy-paste if you like! This is working code
An apology for Prototype Oriented Programming
March 20th, 2009
Prototype Oriented Programming shares Agile guidelines. Do it fast. Focus on the code. Make it clear. And like Agile, it is the most realistic design approach.
Agile rocks. It’s all about making it easy and excellent.
People used to though that simplicity and excellence were incompatibles. They thought that excellence had to be hardly built, structured and of utmost complexity. But in the end it turned out to be unrealistic. The realistic point of view is the more human one, the one that praises human interaction above processes.
Agile is realistic, because is human friendly.
For me, Agile is another reason to use Prototype Oriented Programming. Object Oriented Programming is constrained, hierarchical and structured, and it is thought to be more stable and secure. Actually, it is just harder and more complex, nothing more. Good programmers do things right if they are being pushed to - as constraints do -, but also if they choose freely to do things right. And they do better when they can choose which the best way is. Doing things right is a matter of attitude, not of constraints.
Prototype Oriented Programming is realistic, because is not constrained.
I suppose most of you know little, if any, about Prototype Oriented Programming. What is a prototype? Which are the main differences with Object Oriented Programming? Is Prototype Oriented Programming compatible with classical programming models?
I’ll answer those questions as complete and clear as I can.
Objects that inherit from objects
A prototype is an object, as any other object you have seen in your life. It is an instance of a class - in Prototype Oriented Languages, most cases is an instance of the abstract superclass Object. It has methods, members, etc. This object plays a role as a Prototype - a sample for building more objects.
In Prototype Oriented Programming, objects are cloned from other objects. Classes are replaced by a special non-linguistic type of object called a Prototype after its semantic function. So, to define it in one phrase:
A prototype is an object designed to be cloned and thus serve as a model for new objects.
Semantics over syntax
Classes, in their structure, are indeed objects in disguise. This kind of disguising is not semantic friendly design.
An object is a collection, an aggregation of member objects and methods. A mapping with keys and values, where keys are member names and values are either other objects or methods. It has a memory location address, and it can be referenced by many variables along a program.
A class is exactly the same thing, except because it has two kinds of members: static members, and non-static ones.
In fact, a class is a two-in-one object holding two different collections: one of static class property members, and other of non-static instance property ones.
Now, every new programmer I trained was confused by this state of things. An explanation was mandatory in order to let them understand - the class has two types of uses: one as a container, call it a static object, and one as a factory, a mother of objects.
The role of the class as an object factory is intuitive. "A man is an object that belongs to the class Human". The problem is the class having its own members. Is anti-intuitive: why should Human, after all an abstract idea, have objects instance, concrete objects as members? Human can be, by instance, a politician? Can it wash the street? Have you seen the Human doing something, once in life? Why it has methods? Why it has properties?
There’s a powerful reason. And that same reason shows a model design issue in OOP.
Thankfully, prototype orientation exists, and corrects it.
Just a special role of the object
Once in time people used to think that perfect, ideal forms existed. Non perfect, earthly forms where a clumsy imitation of those ideal forms.
So, there was a division, a categorical, qualitative division between the forms as they were in the ideal world and the forms as we see them.
The ideal had no accidents; the actual ones were plenty with accidents. Those imperfections made them differ from the ideal. They were mere shadows of the ideal form.
Those ideals were generic, universals forms. They were classes of forms.
Following that school - it’s western version called "Classical", and not in vane - humanity tried hard to make perfect statues, perfect people, perfect art. They tried, sometimes in a desperate manner, to make reality match the ideal form. After thousand of failures, people started to think that, after all, perfection was not more than an idea, and reality is just a series of similar cases, not emanations of a perfect model. Men and women don’t come from the class Human: they are born in a very juicy way. They come, imperfectly, plenty of accidents, from another men and women.
In reality, things are done through aggregation of elements: some graphite and a stick become a pencil, a cushion and some steel become a chair; a rose, a bird, grass and a stone road become a garden.
And after the first aggregation comes to existence, may a second aggregation appear sharing some attributes with the first one.
A second or third aggregation imitating the garden doesn’t have to share all attributes with the first. The second may have a violet instead of a rose. The third may not have a bird. Even so we call them gardens. That’s because is difficult to say what attribute needs an aggregation to be classified as garden. But then again, why classifying? Would you call it a garden? Then it is a garden.
Context relevant definitions
A garden is not a garden because the aggregated attributes make it a garden, but because we say "That attributes, together, form a garden". And we make that statement guided not only by a set of predefined attributes, but also by context.
A place with a bird, a rose, a stone road and grass may be a passage in the Ancient Rome. Then it is not a garden; is more likely a ruin.
Also, some flowers at the back of the house may be called a garden too, if they make a beautiful scene.
Garden or not garden is a matter of role, not of attributes. And role varies from context to context.
Classifying the aggregate by its attributes is not useful. Instead, tag it by its role.
Objects are aggregations
When we design an object, we put in it all attributes we think that are crucial to describe its role in the project. A garden is quite a different aggregation if we are talking in an urbanism conference and if we are making poetry.
In Prototype Oriented Programming, objects can be built by adding attributes to them. Their aggregation nature becomes then obvious. So, to create an object that describes a garden as we defined it in the first place, we can build it by adding the rose, the road, the bird and the grass as attributes to an empty new object. And then, we can clone it, and have another garden. And clone it again, changing the rose to a violet. And again.
This first object was cleverly aggregated, matching our definition. Then, it becomes a prototype. A prototype is designed to be cloned, because cloning it makes it easier to have elements with similar attributes. And we think, in this project, that this attributes describe pretty well the role of the garden.
A prototype plays the role of a class, but is an object itself. But as we saw before, the class is structurally an object.
If we assume that, the prototype is the class as it should be: a helper, a pattern for easy object manufacturing.
Prototypes are designed simples and comprehensives, as classes, but we can spend little time in them, because if the prototype misses some non crucial attribute, we can add it in the cloned object when needed. This is a great productivity enhancement in prototypes. Agile implementation, agile particular changes to the model, if needed. No longer extensive argumentation about if a member should or shouldn’t be in the class or the object.
The class as a different linguistic element is an artificial anti-intuitive construct: after satisfying the classical inclinations of its designers, the class as a "perfect untouchable model" showed itself insufficient, and the designers needed to add to it some functions and some variables, betraying the classical model.
It’s not that the betrayal was a mistake. It was needed. The mistake was using classical philosophy as an inspiration, when is widely known to lead to unrealistic conclusions.
Tagging instead of classifying
"A man is an object that belongs to the class Human". A man doesn’t belong to the abstract idea of a Human. Is rather the other way round: the Human idea was developed as a pattern from men.
Once we know that a thing with legs, arms and that talks is a Human, we tag as Human every man and woman we see.
We tag ourselves. We are not tagged a priori. We may have a lot of things in common with the other people we call "Human", but we don’t belong to the class "Human" until someone name ourselves like that.
The classical designer doesn’t mind if, by instance, a man has a leg less. He says "Human has two arms and two legs". I chose this example to show how that kind of statements may lead to factual discrimination. Is not that the classical designer is evil, but is undoubtedly unrealistic.
So, how to start?
Prototype Oriented Languages are most modern languages of the industry. The ones I have tested are:
- PHP: PHP supports dynamic add of object members to an object, and even on-the-fly object creation using the stdClass. But it doesn’t give any support to method adding. For method adding to work in PHP we must rely in a “magic” function of PHP objects that pre-handles all method executions in the object. So, we can redirect the method to be executed using an array of methods. Making it work is not that easy so I’ll publish and explain the code later. The best part is that, once implemented, PHP becomes fully prototype oriented.
- JavaScript: JavaScript is in essence a POL. But its designers though that it would be too hard for developers, hard to accustom, to use prototypes. So they made some changes in the model and is harder to use prototypes in it. But essentially, JavaScript remains a Prototype Oriented Language, and just a little method makes it work as intended. I strongly advise reading Douglas Crockford’s notes about JavaScript. As a side note, Douglas Crockford is the author of JSON.
As far as I know, Python and Ruby are POL, and Perl is POLisheable. But I’ve never tested them and they may need an adaptation, as PHP and JavaScript need.
In a future article I’ll describe how to make Prototype Oriented Programming work in PHP and JavaScript, and the main architectural guidelines for its use.
In fact, with Prototype Oriented Programming, the possibilities are endless: architecture guidelines are mostly consistency advices and reengineering of well-tested architectures for OOP. But you’re not restricted to that, prototypal code is easy and getting mad is harder. Embrace that power.