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.

6 comments:

Stuart 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();

Debasish 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

Roberto 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

Debasish 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.

Anonymous said...

情趣用品,情趣用品,情趣用品,情趣用品,情趣,情趣,情趣,情趣,按摩棒,震動按摩棒,微調按摩棒,情趣按摩棒,逼真按摩棒,G點,跳蛋,跳蛋,跳蛋,性感內衣,飛機杯,充氣娃娃,情趣娃娃,角色扮演,性感睡衣,SM,潤滑液,威而柔,香水,精油,芳香精油,自慰套,自慰,性感吊帶襪,吊帶襪,情趣用品加盟AIO交友愛情館,情人歡愉用品,美女視訊,情色交友,視訊交友,辣妹視訊,美女交友,嘟嘟成人網,成人網站,A片,A片下載,免費A片,免費A片下載愛情公寓,情色,舊情人,情色貼圖,情色文學,情色交友,色情聊天室,色情小說,一葉情貼圖片區,情色小說,色情,色情遊戲,情色視訊,情色電影,aio交友愛情館,色情a片,一夜情,辣妹視訊,視訊聊天室,免費視訊聊天,免費視訊,視訊,視訊美女,美女視訊,視訊交友,視訊聊天,免費視訊聊天室,情人視訊網,影音視訊聊天室,視訊交友90739,成人影片,成人交友,美女交友,微風成人,嘟嘟成人網,成人貼圖,成人電影,A片,豆豆聊天室,聊天室,UT聊天室,尋夢園聊天室,男同志聊天室,UT男同志聊天室,聊天室尋夢園,080聊天室,080苗栗人聊天室,6K聊天室,女同志聊天室,小高聊天室,上班族聊天室,080中部人聊天室,同志聊天室,聊天室交友,中部人聊天室,成人聊天室,一夜情聊天室,情色聊天室,寄情築園小遊戲情境坊歡愉用品,情境坊歡愉用品,情趣用品,成人網站,情人節禮物,情人節,AIO交友愛情館,情色,情色貼圖,情色文學,情色交友,色情聊天室,色情小說,七夕情人節,色情,情色電影,色情網站,辣妹視訊,視訊聊天室,情色視訊,免費視訊聊天,美女視訊,視訊美女,美女交友,美女,情色交友,成人交友,自拍,本土自拍,情人視訊網,視訊交友90739,生日禮物,情色論壇,正妹牆,免費A片下載,AV女優,成人影片,色情A片,成人論壇,情趣,免費成人影片,成人電影,成人影城,愛情公寓,成人影片,保險套,舊情人,微風成人,成人,成人遊戲,成人光碟,色情遊戲,跳蛋,按摩棒,一夜情,男同志聊天室,肛交,口交,性交,援交,免費視訊交友,視訊交友,一葉情貼圖片區,性愛,視訊,視訊聊天,A片,A片下載,免費A片,嘟嘟成人網,寄情築園小遊戲,女同志聊天室,免費視訊聊天室,一夜情聊天室,聊天室