Thursday, December 4, 2008

A work-around for a common Inheritance problem in Javascript

Inheritance in Javascript is a well-documented concept found on the internet. There are quite a few ways to do it but most solutions generally involve prototyping in Javascript. But there are caveats and to understand them, I will demonstrate how Inheritance is typically achieved (through JavaScript prototyping).

Javascript, arguably, supports a form that mimics Class Inheritance through the use of the prototype property accessible to all objects. Remember that in JavaScript, everything is an object, even a function. If you choose to define your "class" using a function, it is actually an object. JavaScript does not support classes but we are still able to model our scripts in an object oriented manner that is good for code reuse, fast execution, and legibility. So first, let us define our "class" (emulation) that will let us extend the GMap2 "class" found in the Google Maps API:

function GMap2Extension(){}
GMap2Extension.protytype = GMap2;

That is all there is to defining and deriving one "class" from another in JavaScript. It is actually a function, which in JavaScript is also an object. But it behaves like a class in most respects in that it has a constructor that can accept arguments and may define public, privileged, and private properties and methods. [Class emulation in JavaScript is beyond the scope of this article but you can find out more about it in another article I will be posting soon or elsewhere on the net.]

That said, again there are a few caveats to watch out for. In this article I will demonstrate a particular problem that relates to extending (sub-classing or inheriting from) JavaScript "classes". The first problem is that the base "class" (function) ((object)) is expecting arguments to be passed into the constructor and may fail (error) without them. So, we need to supply the arguments (parameters) to the the base "class" constructor by rewriting our GMap2 extension "class" (function) ((object)):

function GMap2Extension() { GMap2.apply(this, arguments); }

In the above example we have used the 'apply' function of the GMap2 to do this for us. The 'arguments' parameter is a property available all objects that supplies an object similar to a dictionary. It is simply a dictionary-like object containing all the arguments presented GMap2Extension "class" (function) ((object)). The 'this' parameter is a special JavaScript keywords that refers to the object in-scope, in this case, it will be a GMap2Extension instance (when the constructor is called with the 'new' keyword.

You'll notice I did not supply named parameters in the definition of the GMap2Extension "class" (function) ((object)). In JavaScript, a loosely-typed language, it is unnecessary but here it is with the parameters defined:

function GMap2Extension(container, opt_opts) { GMap2.apply(this,arguments); }

The parameters 'container' and 'opt_opts' simply mirror those found in the GMap2 function definition. If you wanted to overload the constructor to allow you to pass extra arguments for processing in your own constructor, you might compose the function as follows:

function GMap2Extension(message,container,opt_opts) {
this.message = message;
GMap2.apply(this,{"container":container,"opt_opts":opt_opts});
}

Next, we'll examine more closely the use of the prototype property, available to every object in JavaScript, to extend the "class". The prototype property accepts an object and, since a function is an object and we use functions to emulate classes, we can pass a function to the prototype property. JavaScript will copy all the properties from the object (function) (("class")) assigned to the prototype property to itself:

GMap2Extension.prototype = GMap2;

Ok, so it seems our GMap2Extension "class" is ready to go - we'll just instance it using the 'new' keyword and assign it to a variable (once all the objects required to be passed into the constructor have been created):

var mapelement = document.getElementById("mymap");
var mymap = new GMap2Extension("welcome to my map",mapelement); //opt_opts is optional

Everything was looking good, until we execute. It errors. It seems the properties and methods within the GMap2 class cannot be found and there is a good reason for this. Google has wisely placed private and privileged methods and properties within the constructor of their important objects to ensure that there are no accidental (or malicious) usage of these special members.

The only problem is, the subclass, with it's prototype set to GMap2, what is actually stored is an object returned from it's constructor. The base (GMap2) object stored in the prototype no longer has access to it's constructor because it is out of scope and now, the object stored in the prototype property no longer has access to those special members and it cannot complete it's work - it only has access to the public properties.

Another option is to supply the prototype with a new instance of the GMap2 "class". While that may work in other instances, in the case of GMap2, it may be constraining having to know in advance which element will be passed and to not have the freedom to change that. This option is not our solution if we need the freedom to change the map element.

An alternative is, while continuing to use prototyping, we will pass on prototyping the constructor and opt just to prototype the various properties of the GMap2 object:

GMap2Extension.prototype = GMap2;
for(var prop in GMap2.prototype) GMap2Extension.prototype[prop] = GMap2.prototype[prop];

This will give us access to all the properties of the (implicit) base class. The shortcoming with this solution is that a GMap2Extension instance will never evaluate to being an 'instanceof' a GMap2 object - regrettable and unfortunate. However, in a language like JavaScript, duck-typing ("if it walks like a duck...") is pretty common and can give you an edge in other ways that strict-typing cannot.

But we're not satisfied with that - we want to know in our code what base a subclass is derived from. Fortunately, there is another way. Using closures in JavaScript ( a function within a function) we can keep the private and privileged members found in the constructor of the base class alive long after the original constructor has gone out of scope and been garbage collected - as long as we maintain references to the closures. We'll do this with an global function:

function extend(subclass, base)
{
function Closure(){}
Closure.prototype = base.prototype;
subclass.prototype = new Closure();
subclass.prototype.constructor = subclass;
subclass.base = base;
}

function GMap2Extended(message,element)
{
GMap2Extended.base.call(this, element);
this.enableContinuousZoom(); // the GMap2 methods are available
this.mymessage = message;
}

extend(GMap2Extended, GMap2);
var mymap = new GMap2Extended("My map!",document.getElementById("map"));

alert(mymap instanceof GMap2); // alerts true

This works but I wasn't happy with what seemed to be an unnecessary global function. I felt it should be tucked away in a better place and, since Function is also an object, I decided that was where the extend method should reside:

Function.prototype.Extends = function(base){
function Closure(){}
Closure.prototype = base.prototype;
this.prototype = new Closure();
this.prototype.constructor = this.constructor;
this.base = base;
}

You'll notice that there is a new property added: 'base'. For the time being, and until JavaScript version 1.91 is found commonly on most browsers, we are stuck keeping our reference from descendant to ascendant. While the prototype chain exists and might be able to provide that information, we have no way of teasing the type from the object stored in the prototype without at least knowing what it might be before hand. Adding this property ensures that we know exactly which class another derives from. And, we can use this new property to pass arguments to the constructor of the base class. Now extending a base class seems a little more elegant and we're not stuck with a messy global function:

function GMap2Extended(message,element)
{
GMap2Extended.base.call(this, element);
this.enableContinuousZoom(); // the GMap2 methods are available
this.mymessage = message;
}
GMap2Extended.Extends(GMap2);
GMap2Extended.extends(GMap2);
extend(GMap2Extended, GMap2);

var mymap = new GMap2Extended("My map!",document.getElementById("map"));
alert(mymap instanceof GMap2); // alerts true

Tuesday, October 14, 2008

Interface in Javascript

While there are other suggested ways to emulate Interface in JavaScript, I prefer the method I demonstrate (below) because of it's simplicity. If you really want strict enforcement, you'll need a system that implements decorators (see Decorator Pattern) which may provide strict[er] enforcement at run-time but ends up looking a little less than elegant (note the sarcasm).

For my purposes, I just want to assist development of complex JavaScript solutions by reducing complexity and avoiding inadvertent mistakes. This is not a solution that ensures strict enforcement nor are any of the solutions I put forth in writing JavaScript in an OO manner.

In OO terms, an Interface is a contract by which the implementing class (or in the case of JavaScript, a function) adheres. An Interface describes a desired behavior and enforces adherence for any Class which implement the Interface. Implementing interfaces, again in OO terms, is like saying OneClass 'IS LIKE A' NutherClass, or more correctly 'PROMISES TO BEHAVE LIKE', in contrast to Inheritance where you might say that a DerivedClass 'IS A' BaseClass.

As JavaScript applications are becoming increasingly complex with multiple team members participating in the design and construction process, we need a means to enforce the Interface contract beyond just commenting the JavaScript code. The Interface is common in many design patterns and, while we can omit it's use, the consequences are that the programmer[s] must remember all instances where they intend to implement a grouping of functionality or behavior.

Since the Interface is not available in JavaScript, we are forced to emulate it in the most elegant and functional manner we can through JavaScript (read as 'duck typing'). Here for your benefit is my take on a simple way to emulate the Interface in javascript:


function Implements(implementer,pseudoInterface)
{
for (prop in pseudo)
for (prop in pseudoInterface)
if (typeof pseudoInterface[prop] === "function" )
if (typeof implementer[prop] != "function")
throw new Implements.FunctionNotImplemented(implementer.constructor.name,prop,pseudoInterface.constructor.name);
}

Implements.FunctionNotImplemented = function(implementing,implemented,pseudoInterface){
this.implementing = implementing;
this.implemented = implemented;
this.pseudoInterface = pseudoInterface;
};
Implements.FunctionNotImplemented.prototype.message = function(){
return this.implementing + " does not implement function: " + this.implemented + " as contracted in psuedo-interface: " + this.pseudoInterface;
};

function IUpdateable(){}
IUpdateable.prototype.update = function(){};
IUpdateable.prototype.sendupdate = function(){};

function myClass()
{ Implements(this,new IUpdateable());
}
myClass.prototype.update = function(){ alert("this object had it's update method called"); }

function main()
{
try { var myobj = new myClass(); }
catch (e if e instanceof Implements.FunctionNotImplemented) alert(e.message());
catch (e) alert("cannot handle exception: " + e.String()); // log error
}

Notice that it is only at instantiation of the object implementing the interface that a check is performed. You may very well be running code and never see your error unless the offending implementer is instantiated and fails to implement the methods defined in the interface. If we attach our logic to the prototype of Function, we can resolve this problem and also do away with messy global declarations. While we're at it, I'm going to add the ability to implement multiple Interfaces:

Function.prototype._Implements = function(pseudoInterface,opt_options){
for (prop in pseudoInterface.prototype)
if (typeof pseudoInterface.prototype[prop] === "function")
if (typeof this.prototype[prop] != "function")
throw new Function.MethodNotImplemented(this.name,prop,pseudoInterface.name);
};

Function.prototype._ImplementsArray = function(interfaces,opt_options){
if (interfaces instanceof Array)
for (item in interfaces.reverse())
if (typeof interfaces[item] === "function")
this._Implements(interfaces[item],opt_options);
else throw "The Array supplied contains an item that is not a Function";
else throw "The parameter supplied is not an Array";
};

Function.prototype.Implements = function(interfaces,opt_options){
try {
if (interfaces instanceof Array) this._ImplementsArray(interfaces,opt_options);
else if (typeof interfaces === "function") this._Implements(interfaces,opt_options);
else throw "The parameter 'interfaces' supplied was not an Array or Function";
}
catch (e)
{ alert(e.toString()); }
};

That is all well and good but you may have noticed that the implementing object bares no relation to the implemented interface. In other languages, like Java or C#, we can perform a type test to ask if an object IS of a type it has implemented which will result in true. In this way, implementing interfaces behaves like multiple inheritance. Our solution above will not respond the same way with JavaScript instanceof. Because the prototype chain cannot be branched (it is a one-to-one, child-to-parent relationship), our Interface solution appears more like a pseudo-Interface.

Of course, we could insert the Interface(s) at the top of the prototype chain but if our implementing class(es) were derived from classes not implementing the interface, errors would be thrown and brittleness introduced into the solution. This would become, certainly, more of an issue were one deriving from classes in an external package (such as the Google Maps API) where we have no (classical) means to ensure due diligence in regards to the contract defined by an Interface.

Yes, JavaScript is unique in it's flexibility and we can simply add methods (properties with a value of a function) to the prototype of the, for example, GMap2 function. But that is contrary to legibility where, in the case of Google Maps API and other external API's, the package is opaque (through obfuscation, compression, and in some cases encrypted) aside from the public documentation.

Again, JavaScript is unique in this ability but the well-rounded programmer uses several languages that when aggregated, can and should be composed complying (where possible) to a common or similar form within OO style.

Yet I'm still unsatisfied with our inability to use instanceof in detecting a class that implements a given Interface. The solution is to write our own instanceof and attach it to the prototype of Object:


Object.prototype.isInstanceOf = function(pseudoInterface){
if (this instanceof pseudoInterface) return true;
else
{
try { this.constructor.Implements(pseudoInterface); return true; }
catch (e) { return false; }
}
};


And there you have it, a not-too brittle means of implementing interfaces in JavaScript.