Archive for January, 2008

Prototypal Inheritance in JavaScript

Posted by Daniel on January 25, 2008
Programming / No Comments

As anyone who has tried will know, inheritance is really awful in JavaScript. I just watched a really good video from Douglas Crockford that shows how to make prototypal inheritance work well in JavaScript. First, there are two ways to do OOP:

Classical
Essentially every OOP language other than JavaScript. You have “Classes” and each object is a member of a class. For example, Alice might be an object of the class Person.
Prototypal
There are no classes, just objects. Inheritance means “make an object based on this other object and then make these changes”. For example, you might have the object Person, and you create Alice by making it just like Person, but with a specific name.

The problem with JavaScript is not that it is prototypal, but rather that Netscape tried to make a prototypal inheritance that looked classical, and it got neither right. But here is a way to make prototypal inheritance in JS, curtesy of Crockford:

/* This is where the magic happens. */
function object(o) {
    function F() {}
    F.prototype = o;
    return new F();
}
var Alice = {
    name: "Alice",
    run: function() {document.write("Run! Run! Run!")}
};

var Bob = object(Alice);

Here, Alice is just a regular JavaScript object. It has one property and one method. Notice that there is no constructor. To learn why this works, watch Doug’s video.

Right now Bob inherits from Alice. It has the same properties and methods. But we can customize Bob:

Bob.name = "Bob";
Bob.hobbies = ["Science Fiction", "Archery"];

We replaced the name property and add a new property to Bob. But Bob and Alice still share the run() method. But watch this: We can add a new property to Alice, after we created Bob, and Bob will inherit that property also:

Alice.job = "Cryptographer";

Now Bob also has the attribute job, with the value “Cryptographer”, courtesy of Alice.

Private properties

This is where things begin to get uglier. To get private properties in JavaScript you need to use closures (ie. anonymous functions). For example, like this:

var Jimmy = (function() {
    var age = 10;
    return {
        birthDay: function() { age += 1; return age;},
        getAge: function() {return age},
        name: "Jimmy"
    };
})();

What’s happened here is that we made an anonymous function and immediately executed it. The variable age is local to that function, and so it is private. But because it is referenced by the methods, it is not destroyed when we exit the function.

We can also use a closure to get private properties in a child object:

var Sarah = (function() {
    var age = 8;
    var that = object(Jimmy);
    that.birthDay = function() { age += 1; return age; };
    that.name = "Jimmy";
    return that;
})();

Notice that Sarah still has the getAge() method, but that this method still points to the old age variable in Jimmy.

Ruby-like blocks and iterators in JavaScript

Posted by Daniel on January 19, 2008
Programming / No Comments

Ruby is a wonderful language, I love it. I so wish that it was more widely deployed than it is, but with the recent success of Ruby on Rails the situation might improve. Anyways, one thing I miss about Ruby is its blocks and iterators:

5.times {|count| puts count }

array = [1, "hi", 3.14]
array.each { |item| puts item }

While I don’t think you can get the full expressive power of Ruby blocks and iterators in JavaScript, you can definitely get some of it:

Number.prototype.times = function(fn){
     for(var i=0; i<this; i++) fn(i);
};
Array.prototype.each = function(fn) {
     for (var i=0; i<this.length; i++) fn(this[i]);
};

Now we can do this:

/* Notice that we need brackets around the 5. */
(5).times(function(count){
     document.write(count+"<br/>");
});
["Alice","Bob","Eva"].each(
     function(name) {document.write("Hello "+name+"<br/>")}
);

Not quite Ruby, but pretty neat anyways. Just be careful when extending base classes like this; make sure that there aren’t any conflicts. If you think this is cool, take a look at ruby.js from Florian Gross.

Note: Be careful when using libraries that extend base classes (like ruby.js and Prototype). As cool as they are, they create a risk of conflict with your code or other libraries.

Mozilla’s JavaScript 1.6 includes an Array:forEach method, but this is not part of ECMAScript and should not be expected to work in all browsers.

Functional methods in JavaScript

Posted by Daniel on January 11, 2008
Programming / No Comments

In my previous post I talked about JavaScript being a functional language. But those familiar with traditional functional languages like Haskell and ML will notice that JavaScript lacks traditional functional constructs like map, foldl and currying.

I do wish that JavaScript had these constructs by default, and it doesn’t. But at least we can add these constructs ourselves.

var map = function(fn , xs) {
    if (xs.length == 1) return [fn(xs[0])];
    return [fn(xs[0])].concat(map(fn, xs.slice(1)));
};
var foldl = function(fn , x0, xs) {
    if (xs.length == 1) return fn(x0, xs[0]);
    return foldl(fn, fn(x0, xs[0]), xs.slice(1) );
};
var curry = function(fn) {
    /* Yes, I hate this function, why do you ask? */
    function toArray(pseudoarray) {
        var array = [];
        for (var i=0; i<pseudoarray.length; i++)
            array.push(pseudoarray[i]);
        return array;
    }
    var xs = toArray(arguments).slice(1);
    return function() {
        return fn.apply(this, xs.concat(toArray(arguments)));
    };
};

Then you can do things like:

/* Ex 1 */
var double = function(x) {return 2*x};
map(double, [1,2,3,4,5]);

/* Ex 2 */
var mult = function(x,y) { return x*y };
foldl(mult, 1, [2,3,4,5]);

/* Ex 3 */
var product = function(xs) {
    return foldl(function(x,y) { return x*y }, 1, xs);
};
product([1,2,3,4,5]);

/* Ex 4 */
var add = function(a,b) { return a+b; }
var add1 = curry(add, 1);
add1(2);

The misunderstood functional language

Posted by Daniel on January 04, 2008
Programming / No Comments

I have always been interested in functional programming languages. The idea of functions as a first-class citizens is extremely powerful. And as a mathematician, I find great beauty in the pure functional languages like Haskell.

You might then imagine my joy years ago when I discovered that JavaScript is actually a functional language in disguise (albeit not a pure one). As a most elementary example, you can have anonymous functions and assign a function to a variable:

var hello = function() { document.write("Hello world"); };
var greeting = hello;
hello();    // prints "Hello world"
greeting(); // prints "Hello world"

But a functional language can do much more interesting things than that. You can pass functions as parameters and functions can return other functions as output. For example, consider the derivative operator:

// returns the derivative of "f" computed numerically.
var Diff = function(f /* function */) {
    return function(x) {
        var h =0.00001;
        return ( f(x+h) - f(x) ) / h;
    };
};

// Test with a cubic function.
var cubic = function(x) { return x*x*x; };

document.write(cubic(4)); // prints 64
document.write("<br/>");
document.write(Diff(cubic)(4)); // prints 48.0001...
document.write("<br/>");
document.write(Diff(Diff(cubic))(4)); // prints 24.0002...

Can your programming language do THAT?

Functional languages have always had fame for being difficult. It is a neat irony that the language used by millions of novices world wide, and the most used language in the world, would turn out to be a functional language.

Happy New Year – time to get LinkedIn

Posted by Daniel on January 01, 2008
Miscellaneous / No Comments

Happy new year everyone!

A few days ago Jean introduced me to LinkedIn, a professional networking site. You add information about yourself as a professional, much like a CV (profession, experience, specialties, etc). You make connections with other people and build a network. You can search for other people by name, skills, etc.

I just began making my LinkedIn profile and my network. If you’d like to make a connection, just give a shout.

purchase software