Dropping the dependencies

Thursday 08 December 2011

One of my highest priorities right now is to increase browser compatibility. Supporting IE6 probably isn't going to happen, and even IE7 is unlikely. IE8 would certainly be a nice to have given that as of July 2011, about 60% of IE users are using IE8, though that will change. I'd really love to avoid having to write different versions of JavaScript for different browsers, but we shall see...

First up is getting rid of the dependency on WeakMaps or Maps in general. Simple Maps and Sets are due to be in the next version of JavaScript. Without them, you have problems telling the difference between certain types of key, because when you do a plain obj[key] = val, the field name created is just the string representation of key. Thus 1 and "1" are the same thing, and every object is [object Object] - hardly very useful. I need objects as keys.

This one I've managed to work around: I've managed to build an implementation of a Map. Inevitably, it's a compromise, and it ends up storing a unique ID in every object it touches. Currently, it does that via defineProperty (in order to make it non-deletable, non-rewritable and non-enumerable) which is broken in IE8, but I hope to be able to work around that.

The much bigger problem is working around the lack of Proxies in older browsers. Initially, I'll have to build the API out so that you can drive the proxy manually. This will mean that instead of writing code like a.b.c = x.y you'll have to write code like a.get('b').set('c', x.get('y')). Yup, it's pretty grim, and I doubt that'll be the worst of it. I'm hoping to have some sort of mechanised translation, but seeing as you can write

function MyFun (f) {

you're either going to have to do dynamic translation of any f that arrives there (which is OK to a point - f.toString() should give you the source code of f (which I could then parse, build an AST, analyse and rewrite), unless it's a browser built-in), or you're going to have to do whole program analysis in advance and really prepare two different versions of every function and then select at run time which version to run based on whether or not you're inside a transaction. I've not made up my mind which one I prefer - comments welcome - but the first step will be to build out the proxy API so that these things can be driven manually, even if the syntax is pretty ugly.