Wednesday, October 10, 2007

I didn't know Javascript can do this !

The best part of learning a new programming language is the bag of surprises that await you at every line of your program. And it's almost always a mixed bag - things that you were confident of, often do not work the way all the blogs have claimed to be. Your favorite idiom that you have so long used in every design starts falling apart. And you start thinking in a new way, in terms of the language which you have started learning. Sometimes you feel bad when your favorite design pattern finds no place in the laws of the new land, but soon you realize that there is a more idiomatic way of doing the same thing.

I have been a passionate Java programmer for the last eight years and started the journey with the same sinking feeling coming from the land of C and C++. I missed the sleak idioms of memory management using smart pointers, the black magic of template metaprogramming and a host of other techniques and patterns as evangelized by the language called C++. Now when I learn new idioms from languages like Javascript and Ruby, I always try to think how it can be mapped to an equivalent construct in Java. Not that there is always a mapping between the dynamically typed world of Ruby or Javascript and the land of static typing that Java implements. Still it's always an enlightening exercise trying to emulate the best practices of one language in the other.

This post is about one such recent experience with programming in Javascript. I was trying to get some stuff from the front end - I had to write an abstraction which will do some computation based on those values. Some parts of the computation had a fixed algorithm, while some parts varied depending upon the environment and context.

Strategy ! I thought .. this was my first reaction to the solution. Since I am not using a statically typed language as Java, I need not implement the delegation-backed-by-the-polymorphic-hierarchy-of-strategy-classes idiom. And I knew that Javascript supports closures as a higher level of abstraction, which I can use to model the pluggability that the variable part of the abstraction demands. Depending upon the context, a different closure will be passed, and I could make the variable component a closure and pass it along into the main computation routine. But the problem comes up when you have multiple such variabilities to model in the same abstraction. For every such variable point, you need to pass a closure as an argument.


// closures as arguments
function WageCalculation(taxCalculator, allowanceCalculator, ...) {
    //..
}



Works, but may not be the best way to model in Javascript. After some more digging, I came across the details of the Execution Context in Javascript. All Javascript code gets executed in an execution context and all identifiers are resolved based on the scope chain and an activation object. And Javascript offers a keyword this, which gets assigned as part of the process for setting up of execution context. The value assigned to this refers to an object, whose properties become visible to accessors prefixed with the this keyword in the main function. Hence all variabilities of the abstraction can be made part of this context and made available to the main computation routine through the this keyword. And this is exactly what Function.call() and Function.apply() do for us!

Simplifying my example to some extent for brevity, let us say that we are trying to abstract a routine for computing the wages of employees. The wage calculation contains a few components, the basic wage, the tax and allowance. Of these, the percentage of tax varies depending upon the category of the employee, while the other components follow a fixed algorithm. For simplicity, I assume hard coded values for each of them, but applying the variation where necessary.

The basic abstraction looks like the following :


WageCalc = function() {

    // privileged method
    this.taxCalc = function() {
        // 20% of basic wage
        return 0.2;
    };

    // private static
    allowanceCalc = function() {
        // 50% of basic wage
        return 0.5;
    };

    this.wage = function(basic) {
        // and the calculation
        return basic - this.taxCalc() * basic + allowanceCalc() * basic;
    }
};



and I invoke the calculation method as :


var w = new WageCalc();
print(w.wage(1000));



for a basic wage of $1000. The tax calculation component (taxCalc()) is a variable part and has been tagged with the this keyword. This is the candidate that I need to implement as a strategy and plug in different implementations depending on the context. If I want to have another implementation where the tax percentage is 30, instead of 20, I just do the following ..


MyWageCalc = function() {

    this.taxCalc = function() {
        return 0.3;
    };
};



and invoke the wage calculation function, passing in the new function object as the context. This is what the apply method of Javascript Function does :


var w = new WageCalc();
print(w.wage.apply(new MyWageCalc(), [5000]));



Here new MyWageCalc() sets up the new context on which the this.taxCalc() of wage() method operates. Hence the new tax calculation functions with 30% of the basic and not the 20% as defined in WageCalc() function.

I have only started to learn Javascript, hence I am not sure if this is the most idiomatic way of solving the problem at hand. But to me it appears to be exciting enough to share in an entire blog post.

5 comments:

Anonymous said...

Interesting notes...

I'm a bit confused though, about your comments for the methods in your WageCalc class.

this.taxCalc is noted as privileged, however anyone can call it, change it, or override it.

the allowanceCalc also (IIRC) needs a 'var' before it, otherwise in JavaScript it is a global method on the window, thus not private in any way.

var allowanceCalc = function(){
// 50% of basic wage
return 0.5;
};

With the 'var' declaration, it is scoped to the WageCalc Class, and can't be directly called like...

var allowanceCalcValue = new WageCalc(1000).allowanceCalc();

Unknown said...

@Stuart: I am learning Javascript, hence I may be wrong. But let me clarify my understanding ..

In the example, this.taxCalc is privileged in the sense that Crockford describes here. A privileged method is one that is able to access the private variables and methods, and is itself accessible to the public methods and the outside.

The closure allowanceCalc is private static as described here.

Anonymous said...

Dude Web 2.1!
http://en.wikipedia.org/wiki/Web_2.1

Unknown said...

Heyy
I see you like to make things look like java, so with the code in the bottom of this comment you can define classes and make use of inhetihance like this:

var Clazz = Class.create({
prop1 : null,
propX : "BLABLABLA",

initialize : function(){
// constructor
}

method1 : function(){
// TODO Impl
}

// etc
});

var SubClazz = Class.extend(Clazz, {
prop1 : "OVERRIDED",

method1 : function(){
// js is fun
alert(propX); // BLABLABLA
alert(prop1); // OVERRIDED
}
});

/******************************/
gOT IT????
/******************************/

tHE MAGIC CODE TO MAKE THIS POSSIBLE:

/**
* Implements object extendability in the Object definition.
* @param {Object} destination The code implementing the extensions.
* @param {Object} source The source to be extended.
*/
Object.extend = function(destination, source){
for (var property in source)
destination[property] = source[property];

return destination;
}

/**
* Definition of a Class.
* Represents the OOP concepts of a Class.
*/
var Class = {
/**
* Defines and creates a new Class instance.
*
* @param {Object} impl The implementation of the class being created.
* @return {Object} The class defined.
*/
create: function(impl){
// TODO THROW NEW EXCEPTION IF IMPL NOT VALID
var clazz = function(){
// TODO IMPLEMENT EXCETION CATCHING FOR LOGGIN, AS WELL AS THE LOGGIN COMMANDS IT SELF
if (this.initialize) this.initialize.apply(this, arguments);
else if (this.superClass.initialize) this.superClass.initialize.apply(this, arguments);
};
clazz.prototype.superClass = Object.prototype;
if (impl && (typeof(impl) == "object")) clazz.prototype = impl;
return clazz;
},

/**
* Defines and creates a new Class instance based on a given SuperClass.
* Represents the OOP concept of inheritance providing a way of defining a SubClass.
*
* @param {Object} source The Class to be extended.
* @param {Object} additions The Subclass implementation.
* @return {Obejct} the subclass defined.
*/
extend: function(source,additions){
// TODO THROW NEW EXCEPTION IF IMPL NOT VALID
var clazz = Class.create();

if (source.prototype) Object.extend(clazz.prototype ,source.prototype);
Object.extend(clazz.prototype, additions);

clazz.prototype.superClass = source.prototype;
return clazz;
},

/**
* Defines a static Class.
* Represents the OOP concept of a static Class.
* It actualy returns an object instance of the class defined.
*
* @param {Object} impl The Class implementation.
* @return {Object} The static class defined.
*/
createStatic: function(impl){
var clazz = this.create(impl);
return new clazz();
}
}


hope you like this!
hlobo@inf.ufsc.br

Unknown said...

@Roberto: Thanks for your feedback. Just a quick point on inheritance - inheritance enforces stronger coupling between classes and hence may not be the best solution in this case. Closures provide a more natural way of implementing strategy like design pattern. For more on the evils of inheritance, have a look here.