speaking of

code ruminations and whatever else strikes my fancy

13 October 2009

prototypal inheritance contra template languages

Maintaining old template code is frustrating. The longer and larger conditional clauses and inherited blocks become, the less readable the code. It is hard to understand why at this point in the development of web applications we are still generating our very tree-like HTML as if it were a flat file. Given how slowly browsers change, it is not likely we will be moving to another format any time soon. Friction occurs between the declarative structure of HTML and the procedural programming language meant to generate it (e.g. Django, Cheetah). The template accumulates cruft faster than other components because it is always a poor attempt at both procedural and declarative code.



Looking at HTML as a tree, one solution would be to write HTML using a language that is naturally tree-structured. Functional languages fit this mold. This will only be a maintenance boon if application logic is in a language such as Erlang or Haskell.



Since most application logic is written in a procedural language (Python, Ruby, Java), why not handle the creation of HTML in this way? We already have a model in the browser for HTML manipulation idiom for procedural programming: jQuery. jQuery's growing popularity is due to the simplicity with which one can describe DOM manipulations. Bringing this model to the server side would improve clarity of front-end code in the same manner that it has done on the client side.



Consider a block of HTML describing a rudimentary document:




<html>
<head>
<title>A Document</title>
</head>
<body>
<div id="content">
<ol class="things">
<li>Example Thing</li>
</ol>
</div>
</body>
</html>


Think of this block as the prototype of the thing we want to describe by means of a procedure. Instead of aiming to build exactly and only the output we desire, the proper output will be achieved by starting at a clear example and proceeding through a series of modifications. This strategy is borrowed from the prototypal inheritance found in languages like Javascript.



The following code is an example of a potential API for Python. It should look very familiar to anyone who has written jQuery.




html = Q(html_doc) # load the above DOM into a jQuery-like object
html('title').text = 'A More Interesting Title'
for i, item in enumerate(html('#content ol li').remove().duplicate(10)):
item.text = str(i) + ' item!'
html('#content ol').append(item)
html.render()


Template-based HTML generation is by contrast the class-based inheritance model of the frontend world. It has all the same complexity problems. Over time, templates that take advantage of inheritance (such as blocks in Django or Cheetah) will require a reader to look at several files at once to reconstruct the execution of the template. Cleverness is obfuscation. Deep inheritance trees are inarguably clever.



One may object that providing no way for non-programmers to create HTML would cause friction between designers and programmers. Under the prototypal model, a designer's mockups are the prototypes that are inputs to the procedure. Non-programmers frequently write poor code, which contributes to the maintenance burden. Recognizing that building the HTML output for any application requires a programmer, one ought to provide them immediately with the most powerful tools for clearly expressing HTML. There is no better one than the language and style in which they are building the application.



Does this sound interesting? I started a project to implement it for Python using the lxml libxml2-backed library. Check out pyQuery on github. Contributors are welcome.

10 September 2009

How to use 'this' in javascript

The usual complaint levied against javascript's object model is that the 'this' keyword does not work as expected.




var frobber = {
'frobval': 'foobar',
'frob': function() {
return this.frobval;
}
};
frobber.frob(); // works
var slorp = frobber.frob;
slorp(); // fail!


Most people expect, due to experience with languages like python and the overloaded meaning of 'this' that context follows the method. The only serious mistake the javascript designers made was choosing the wrong name for the context and redefining its meaning. This surprises users.



In an attempt to fix this, many libraries have been written that bolt familiar class-based inheritance on javascript's prototypal inheritance model. This inevitably results in kludgy code and unhelpful but necessary boilerplate. When treated as a feature rather than a deficiency, less meaningless syntax is required and readability of the code increases.



Javascript is lexically scoped by function boundaries.



Most problems using this model occur because javascript is most often used in an event-driven environment, such as the browser. One passes a function as a callback for some user-initiated event.




window.onclick = frobber.frob; // fail!


By default, event handlers follow the natural context. Within the click handler, 'this' will be the object that owns the onclick property, as if the browser is calling the handler by reference to the property.




window.onclick();


The above code is syntactic sugar for using the call function.




window['onclick'].call(window);


Javascript provides call and apply for executing functions with context. These are the simplest and clearest ways to execute a function. Beefy class-inheritance libraries require the user to constantly massage 'this' into familiar usage.



Javascript's inheritance model is prototype-based.



The real cement for this natural usage of 'this' is javascript's prototype-based inheritance. In this model, there is no distinction between classes and instances. Any instance object can be the prototype of any other instances. Property resolution ([] or . subscripting) searches the object that is subscripted before continuing up the prototype chain. Consider what would happen if a function retained context after being separated from its instance in the following example.




var a = {
'actions': [],
'act': function() {
this.actions.push('action');
}
};
a.act();
a.act();

var B = function() {
this.actions = []; // shadow actions in object a
};
B.prototype = a;
var b = new B();
b.act();


a.act and b.act are the same function. b does not inherit act from an abstract, but rather an instance. If b did not have the actions property, it would inherit the property from a. a.act and b.act would modify the array of actions in the prototype instance. This differs from the class-based inheritance model where there is one instance and a class hierarchy to traverse for property resolution. Prototype-based inheritance makes a poor basis for class-based inheritance models and misses the value and simplicity of prototypes.



For the cases when one wants a method-like call, it can easily be written by using a closure, the most useful feature in any programming language.




window.onclick = function() {
frobber.frob();
};

// or more generally with partial application

var method = function(self, fun) {
if (typeof fun == 'string') {
fun = self[fun];
}
var args = Array.prototype.slice(arguments, 2);
return function() {
return fun.apply(context, args.concat(arguments));
};
};

window.onclick = method(frobber, 'frob');


Because javascript has syntactically light closures, the usefulness of a function like 'method' goes down with the more common function features it supports. It is often easier both to write and subsequently understand a closure than one of its generalized counterparts, such as 'method' above.



An example: iteration



Most javascript libraries provide a function for iterating the values in an array or array-like object. this is how iteration should be written given the above discussion.




var $break = {};
var each = function(iterable, fun) {
for (var i = 0, len = iterable.length; ++i) {
if (i in this && fun.call(this, iterable[i], i, iterable) === $break) {
break;
}
}
};


Most iteration functions include a third parameter for setting the context object for the function argument. This is surprising given the way context works naturally in javascript. With the above iteration function, assigning it to an object, calling, and applying all work as anticipated.




frobber.each = each;

frobber.each([true, false, true], function(b) {
this.value = this.value || b;
});

var sumStuff = function(n) {
this.stuff += n;
};

each.call(b, [1, 2, 3, 4, 5], sumStuff);


I am aware that javascript's Array.prototype includes each, filter, and map that I have asserted violate the natural intent of the language. I do not believe that these functions used as such increase the readability of code.

11 February 2009

adventures with javascript prototyping

Javascript is a prototype-based language, yet I have only ever seen this mechanism used seriously to bolt on OO class hierarchies of one kind or another. Each has its own weaknesses, but all fail to recognize that classes of the OO persuasion are conspicuously missing for a good reason. Javascript has more in common with so-called functional languages than the abomination with which it shares a name. In an attempt to take seriously this feature, I propose the following function.


var heir = function(ancestor) {
var cons = function() {};
cons.prototype = ancestor;
return new cons();
};

The heir function creates an anonymous constructor, set the argument as the prototype, and returns a new object. The return value will inherit all properties from the ancestor (including the constructor, should one exist). In addition, changes to properties in the ancestor will propagate into its heirs.

In mozilla-based browsers, this can even be done with any object on the fly. Naturally, such a useful operation escapes the dullards engineers at Microsoft.


var heir = {};
heir.__proto__ = ancestor;

caveats


writing to heirs


Properties in the prototype chain that are Objects, like Array, may cause confusion in usage if a coder wishes to modify an heir. Consider the following example.


var a = { 'foo': [1, 2, 3] };
var b = heir(a);
b.foo.push(4);

It is not clear by reading the code that the author intended to modify the ancestor, thus affecting other objects that may be heirs of var a.

deleting keys


Using the javascript delete operator may not produce the desired effect in cases of inconspicuous usage.


var a = { 'foo': true };
var b = heir(a);
delete b.foo;

Deletion only works on the direct properties of an object, not inherited ones. The property "foo" will still be there. The only workaround is to mask the prototype's property with an undefined value of the same name.


b.foo = undefined;

The property "foo" will still be enumerable and appear in for-in iteration.

improving performance over copying properties


Hier is not intended as a performance-enhancing way of copying properties between objects because there are too many side effects of utilizing the prototype chain for property inheritance. Instead, coders should seek to use it for what it provides. A good way to manage these features might be through the addition of methods to the initial prototype of the inheritance chain that provide an API for getting, setting, and removing properties.

one possible usage


Settings objects are often created by copying properties from an Object containting defaults and then subsequently copying properties passed in from another source, masking them.


var def = { 'foo': true, 'bar': false, 'baz': 7 };
var settings = { 'baz': 9, 'bar': true };
for (var k in settings) { def[k] = settings[k]; }

The heir pattern can solve this problem by making the settings object an heir of the def object. In addition, settings will inherit any new properties added to def in the future.

what else?


I plan to elaborate other uses of this pattern in future posts.

about me

My Photo
San Francisco, CA, United States