Tuesday, September 14, 2010

My Own Take On Duck Typing And Javascript

Duck typing is a formalized conception for an aspect of dynamic languages that allows a user to define the type of object by the programmer's use of an object versus by it's OO inheritance chain. It is basically the polymorphic nature of a overloaded function's parameter proxy applied to all objects in the same manner as the base object prototype inheritence chain applies to all objects in Javascript.

I'll admit that I have only recently discovered the coinage of this term, but I've been developing from this perspective for a majority of my work in my Javascript framework. And although it's nice to have a word to describe what it is I've been doing it's a shame that I cannot claim ownership of the concept ;)

I do however have a slightly different perspective on the approach. According to wikipedia the cheif complaint of Duck Typing is the following:

For instance, in Python, you could easily create a class called Wine, which expects a class implementing the "press" attribute as an ingredient. However, a class called Trousers might also implement the press() method. With Duck Typing, in order to prevent strange, hard-to-detect errors, the developer needs to be aware of each potential use of the method "press", even when it's conceptually unrelated to what he or she is working on. (source: http://en.wikipedia.org/wiki/Duck_typing)


Despite the example being extremely poor (why in the world a developer would write a function responsible for accepting both a grape and a trouser object, and do so without realizing that the press methods of each type would be different is beyond me.) However that's not to say the criticism isn't legitimate. I would also contend that the press method itself should type check or implementation check its object before allowing much real damage to occur when you press a bunch of grapes in a trouser press - though if the method didn't, then you'd have a pretty poor trouser press operator function.

Error detection isn't really a problem either. If you're operating with a grape when you thought you had a trouser and you press it expecting ironed trousers well then your code isn't going to do what you expect. But simple inspection of the call stack will clue you in to the fact that your press function was called on a trouser class. Even in weakly typed languages you can still test the type of the object you're dealing with.

In Javascript we have the notion of prototypal inheritence which allows for things like:


Object.prototype.press = function() { };

Trouser.prototype.press = function() {
//clean and press pants
};

Wine.prototype.press = function() {
//murder all the grapes
};

function RoboPressDestructor2000() {
arguments.each(function(param) {
param.press(); //RoboPressDestructor2000 does not care about what it presses
});
}


Which means the developer only has to declare three functions to avoid the problem of try catch proliferation in duck typed code (or EAFP.) In my world Wine and Trousers are all that get pressed - you can press other objects but alas they are like Superman. You can pass what you like to RoboPressDestructor2000 and the application will behave as expected without fail. Knowing that you shouldn't pass in eyeballs to the RoboPressDestructor2000 is up to you. If you're writing code and you don't know the impact of that code then it's your own fault.

But I think the real problem with how Duck Typing is explored in the wikipedia article is that dealing with the concrete implementations of objects is not very beneficial to the developer. In the case above, it's very unlikely that I would have a press function in the real world. But Javascript's implementation lends to a different perspective.

In Javascript you have the following base prototype objects:


Object
String
Array
Number
Date
Function
RegExp
Boolean


Applying Duck Typing to these base classes yields two benefits. First you start thinking about objects in terms of their data instead of their real world representations. And second coding towards that mental model allows for reuse of code almost indefinitely.

For instance:


Object.prototype.escape = function() {
return this; //we'll leave objects open to their interpretation
};

String.prototype.escape = function() {
return EncodeURIComponent(this);
};

Array.prototype.escape = function() {
return this.each(function(o) {
return o.escape();
});
};


I have now created an environment where I can call "escape" on any object and expect the result to be an escaped object - regardless of the circumstances. [NOTE: For clarity sake I'm using an assumed Array.prototype.each function.] This means my X-Browser normalizing function JSON.stringify no longer needs to worry about implementing it's own escaping functions, neither do my form data submission functions or my insert data into a database functions.

So when you start looking at Duck Typing from the perspective of standard programming constructs you enter a realm of meta programming that reduces the complexity of code with a very natural pattern.