Monday, April 13, 2009

ECMAScript 5, I've got needs!

ECMAScript 5... because 3.1 and 4 drowned in politics? Nah, not really -- the relatively superficial update of 3.1 prevailed (because that's what we need after 10 years and the mass migration of applications to the web, right?). Snark: I'm not sure how I feel about standardizing libraries such as for JSON nor the push for generators; perhaps my Scheme roots are showing.

I wanted to submit a comment about the incomplete meta programming capabilities that cropped up in my work on membranes, but I couldn't understand the spec. Perhaps someone has a better shot, because these I actually do care about (and don't relate to the DOM):

The problems occurred when I was trying to create a shadow-copy of an object where I would add funny behavior whenever a call on the shadow would get proxied to the original. The motivation was to enable an application to take one of its objects and communicate it to an untrusted application, and by only sending shadow copies, guarentee the untrusted receiver couldn't get access to the privileged, original objects (or any other privileged ones made accessible by them via potential object graphs). Proxying generally worked. I'd create a new object, look at the (shallow) fields of the original object, and then define setters and getters on the copy for those fields to do all the proxying magic. There is some fun(ny) recursiveness necessary to get this membrane right, and, if you care, I can send you our paper about it.

A lot of important encapsulation and consistency considerations occur, which is important if we want people to be writing secure mashups in JavaScript without resorting to annoying subsets:

  1. What about proxying the definition and extraction of setter and getter functions? Can we redefine the getter and setter for the functions to get, set, and use them?
  2. What about the setters and getters for the prototype field?
  3. It's impossible to define the getter for a missing field (not as much of a security problem, but a huge expressitivity gap, which hit me hard here)
  4. Root prototype poisoning. It should be possible to define new 'root' prototype instances, making it more natural to protect and pass around privileged objects.
  5. Adding and deleting fields should also be introspectable and adviseable.
There are features that I think would be neat, like guarenteed tail-call optimizations, but I view the lack of the above as fundamental weaknesses and incomplete specifications. I can trampoline recursive code pretty easily, but we don't see how to write secure membranes around arbitrary JavaScript objects without these (or writing a BetterJavaScript=>JavaScript compiler, which is stupid as these are basic).

Regardless, at this point, I'm happy to get anything! The committee has gone through a lot, and there's a lot of pressure on making sure what they release does not have holes. Perhaps that's my meta-problem with the whole process: without a benevolent dictator and given the emphasis on folks writing standards compliant code, there is too much pressure against adding fundamental features and not enough for fixing the code we're writing today. At least that means whatever gets through is probably good :)

Addendum: I really, really want weak references, or at least a dictionary with weak references. Adobe already provides this and I think Microsoft does too. JavaScript is typically used in reactive settings, so this would be a big expressive win. Again, I can implement my own TCO or macro system on top, but weak references seem too deep. (Addendum 2: the lack of weak references led to potential memory leaks in both Flapjax and the membrane system. They're an important building block.)


Rapha said...

What about using Rhino for weak references?

Leo Meyerovich said...

A lot of ECMAScript implementations have them -- the problem is that the *spec* doesn't.

Given the general assumption that any JS project starts with a framework being built on top, supporting weak references seems useful.