30.04.10

Leadership by example

From an analysis of preliminary Iraqi election results a month ago:

Many democracies, especially those that have been given their impetus by outside power, hold successful elections once or twice, then have their weak institutions perverted by “strong men” — by which is meant leaders that come to power legitimately then refuse to return it, either doing away with the institutions and practices of representative government or turning them into formulaic but meaningless (think East German elections) hypocricy [sic] that fool no one, least of all their own citizens.

When one considers mistakes of other countries, it makes George Washington‘s example all the more remarkable. Washington took the oath of office 221 years ago today to become the first President of the United States; approximately eight years later he gracefully left office, enabling a smooth and peaceful transfer of power to John Adams. This was not the first time he had set aside power for the good of all: he did likewise years before upon completion of the Revolutionary War, leaving public life rather than remain commander-in-chief or choose another position. (Contrary to popular belief, Washington did not decline a kingship. Moreover, that such an offer could have been credible is dubious given the sentiments in contemporary sources such as The Federalist Papers.)

If he does that, he will be the greatest man in the world.

King George III, upon hearing that Washington planned to “return to his farm” after winning the Revolutionary War

Happy First Inauguration, Mr. President.

16.04.10

More SpiderMonkey changes: ancient, esoteric, very rarely used syntax for creating getters and setters is being removed

tl;dr

We’ve removed support for a handful of obsolete getter/setter syntaxes in SpiderMonkey and Mozilla. This does not include { get property() { return "value"; }, set property(v) { } }, which is widely used and which is part of the latest standard. If you don’t get any syntax errors with your code, you don’t need to worry about this. If you do, skip to the end for details on how to adjust your code to cope. But really, you should read it all for the sheer joy of learning about all sorts of awful syntax you didn’t even know existed before it went away. [Or at least empathize with us liberated SpiderMonkey hackers. :-D])

Properties in JavaScript and ECMAScript 3

The fundamental data structure in JavaScript is the object: a container mapping names to values through properties. You can add, remove, or change the value associated with any property, so long as the property may be modified. All user-defined properties are infinitely modifiable in any of these ways; only a few properties defined by ECMAScript (the standard on which JavaScript is based) are not fully modifiable.

var obj1 = {};
obj.property = 17; // add
var obj2 = { property: 42 }; // add from birth
obj2.property = 17; // change it
delete obj2.property; // remove it

Properties which store values are useful, but what if you want properties which can do things when you interact with them? What if you want to have properties which map strings to lazily-computed values? Or what if you want setting a property to have side effects (as, for example, setting an array’s length to 0 removes all elements in it)?

Properties with getters and setters in JavaScript

If you want properties which have functionality beyond just holding a value, you need getters and setters, stored within accessor properties. (Properties which hold values are called data properties.) JavaScript has long included extensions to ECMAScript to create accessor properties, both syntactic:

var o1 =
  {
    get property() { print("gotten!"); return "get"; },
    set property(v) { print("sotten!  " + v); }
  };
var v1 = o1.property; // prints "gotten!", v1 === "get"
o1.property = "new"; // prints "sotten!  new"

…and programmatic:

var o2 = {};
o2.__defineGetter__("property", function() { print("gotten!"); return "get"; });
o2.__defineSetter__("property", function(v) { print("sotten!  " + v); });
var v2 = o2.property; // prints "gotten!", v2 === "get"
o2.property = "new"; // prints "sotten!  new"

Getters and setters are now part of ES5. The syntax demonstrated above is valid ES5; a different API, Object.defineProperty, provides more flexible support for specifying getters and setters dynamically. Developers using the old-school APIs should begin updating to use the new API as browsers make new releases supporting it. Firefox in particular will include support for Object.defineProperty in its next major release, likely to occur in the latter half of the year.

Examining antediluvian accessor syntax

Unbeknownst to the vast majority of web developers, extension developers, and even Mozilla developers, in the past JavaScript has included other getter and setter syntaxes.

Named ES5-like getters and setters

If you look up the function that acts as the getter given ES5-standard getter syntax, what’s the name of that function?

var o = { get property() { return "get"; } };
print(Object.getOwnPropertyDescriptor(o, "property").get.name);

There are a couple plausible answers here: “anonymous“, “property” (the property name), or “” (the empty string) might be reasonable. JavaScript and ES5 arbitrarily create the getter or setter as a function whose name is the empty string. What if you wanted to name that function? (Bear with me for a moment and pretend this is a compelling need, and that adding a named getter or setter programmatically is absolutely unacceptable.)

Solely by accident of implementation, in the past SpiderMonkey has parsed the following syntax to assign names to getter and setter functions:

var o = { get property getter() { return "get"; } };
// Prints "Name: getter" in past versions of SpiderMonkey (or would if
// Object.getOwnPropertyDescriptor existed; __lookupGetter__ is a
// simple workaround); previous line is syntax error elsewhere
print("Name: " + Object.getOwnPropertyDescriptor(o, "property").get.name);

SpiderMonkey internally implemented the parsing of literal getters and setters by parsing them as though the start of a function expression had just been parsed:

// Faked-up parser state when parsing normal getters/setters
var o = { get property () { } };
                       ↑
function () { }
         ↑

Function expressions may be named or unnamed, but this wasn’t originally considered, so in the above example getter is treated as the name of the function created to correspond to the getter:

// Faked-up parser state when parsing named-getter-function syntax
var o = { get property getter() { } };
                       ↑
function getter() { }
         ↑

No other JS engine accepts this unintentional accessor-method name token.

Getters and setters in object literals

Possibly the best-known additional syntax is for specifying getters and setters in object literals. This syntax was the original Netscape invention for getters and setters; in practice it was superseded by the newer, more function-looking syntax. SpiderMonkey is again the only engine to implement it.

function g() { print("gotten!"); return "get"; }
var o1 =
  {
    property getter: g,
    property setter: function(v) { print("sotten!  " + v); }
  };
var v1 = o1.property; // prints "gotten!", v1 === "get"
o1.property = "new"; // prints "sotten!"

This accessor property syntax has one large advantage over the more-common syntax previously demonstrated (and even over the unintentional named-accessor mistake shown in the previous section). Where you see property in the object literal above, you could instead see a numeric literal, or a string literal — just as you might see either in any object literal without getters or setters, e.g. { 1: "value", "o": "hai" }. Historically, in get property() { ... }, property was required to be an identifier, thus excluding numbers and non-identifier accessor properties from representation. The syntax here had the further advantage of allowing serialization to “source” (more accurately, a reasonable but not always equivalent facsimile) of objects containing non-identifier-named accessor properties, through another Netscape extension in JavaScript.

This syntax also has a few disadvantages. Since the getter and setter contextual keywords follow the property name, the eye must scan past the property name to determine whether a portion of a literal represents a data property or an accessor property. This special-case check also complicates parsing, because now the parser has to check for something beyond just a colon at such locations. (To be sure, this problem exists with get foo() { }, but it’s restricted to the single leading token get, not to all leading tokens.) Since the value assigned to the getter is parsed as an arbitrary expression, there’s no guarantee the value must be a function — that must be checked at runtime.

Assigning getters and setters to properties

This accessor syntax provides the same functionality as Object.defineProperty(obj, propname, { get: fun, enumerable: true, configurable: true }) (mutatis mutandis for setters), except as part of the language syntax rather than as part of its standard library. Again, no other engine has implemented this syntax.

var o = {};
o.property getter = function() { print("gotten!"); return "get" };
o.property setter = function() { print("sotten!"); };
var v = o.property; // prints "gotten!", v === "get"
o.property = "new"; // prints "sotten!"

This syntax is also obscure: outside SpiderMonkey source and test files, only a single file in the Mozilla source code uses it. Strangely, a trawl through AMO shows half a dozen extensions have managed to discover this syntax, despite its near-complete disuse in Mozilla itself.

Assigning getters and setters to names rather than properties

Syntactically, this is just a different flavor of the previous example:

varname getter = function() { return "get"; };
var q = varname; // "get"

Semantically, however, it’s a rather different beast. The problem is that not all names are alike in SpiderMonkey. While ECMAScript specifies all name accesses in terms of objects (pure-JS objects in ES3, tighter spec-internal artifacts in ES5), most if not all JS engines out there optimize name access based on the type of the name. Local and enclosing variable access may be some number of pointer jumps, comparisons, and an offset, rather than some sort of hash table lookup in a more general case. Global variable access can in many circumstances skip lookups in enclosing scopes, going to the global object directly. (Last and certainly least, variable access inside with almost necessarily must be essentially unoptimized and dog-slow. Friends don’t let friends use with!) These sorts of optimizations rely on names always being plain old values, not accessors (except in the global case, where the type of optimizations implemented are qualitatively quite different). Slowing down local or enclosing variable accesses just to support this very rare case would be insane.

SpiderMonkey actually hasn’t supported this syntax for awhile. I only mention it because SpiderMonkey includes code specifically to exclude it. If this syntax is seen and varname can be resolved to a var, it’s a compile-time syntax error. Otherwise, if varname resolves to a var at runtime (possible in the presence of with or eval), it’s a runtime TypeError. Last, if it doesn’t, it “works” — and you are most likely Jesse, combining syntax and features in obscure and evil ways solely to make SpiderMonkey developers’ lives hard. ;-) In sufficiently old versions of Firefox where these restrictions weren’t in place, it’s entirely conceivable this syntax may have resulted in security vulnerabilities (one large factor in its removal from SpiderMonkey).

Prefixed function expressions

Perhaps the most bizarre getter/setter syntax is a modification of the syntax for function expressions and statements. As with all the others, this syntax has only been implemented by SpiderMonkey.

getter function foo() { return "foo getter"; };
var v = foo; // "foo getter"
var q = setter function bar(v) { };

When the prefixed function is a statement in the global scope, the syntax is equivalent to Object.defineProperty(globalObject, "foo", { get: function foo() { /* ... */ }, enumerable: true, configurable: true }) (mutatis mutandis for setter). If it’s a statement in a function scope or an expression that’s not a statement, the prefix serves no purpose that I can discern, except that it affects Function.prototype.toString()‘s behavior by including the prefix in the returned string.

None of these old getter/setter syntaxes provide value

Now that ES5 has codified The One True Syntax and The One True Programmatic API, these older syntaxes bring little to the table.

  • The mistaken ES5-like named accessor get property funname() { } syntax doesn’t satisfy a compelling need.
  • property getter: in object literals provides one compelling feature: the ability to have non-identifier-named properties. As ES5’s get property() { } syntax includes these further extensions beyond what engines have already implemented, this advantage no longer exists:
    var o =
      {
        get name() { return "names valid"; },
        set break() { this.x = "keywords too"; },
        set 1() { this.y = "numeric literals also accepted"; },
        get "custom string"() { return "arbitrary string literals too!"; }
      };
    

    (property getter: has a final advantage with respect to an ancient Netscape extension, but given that extension’s dubious future I will omit the details. Suffice it to say the use case is highly esoteric, and reasonably graceful degradation is possible without property getter:.)

  • getter = and getter function are fully subsumed by Object.defineProperty.
  • varname getter = was already gone.

In sum: these syntaxes make some things slightly easier, but they don’t provide anything you can’t do with ES5’s standardized accessor support.

These syntaxes were the source of numerous bugs

In addition to not being particularly useful, these syntaxes imposed notable costs on development. Supporting so many different getter and setter syntaxes isn’t easy, and the relevant code paths are quite complicated, attempting to decide when which syntax is correct and when not (particularly as far as object serialization is concerned). This has resulted in a multitude of accessor bugs usually found by Jesse‘s fuzz-testing and almost never by real-world scripts: bugs which, in C or C++, can often lead to memory-unsafety and, in the extreme, arbitrary code execution. By my count SpiderMonkey has sixteen separate tests (corresponding to the same number of bugs) dedicated to edge cases and corner behaviors with these syntaxes: syntaxes no one uses, syntaxes superseded by newer and better ones, and syntaxes which no other JS engine currently supports, nor ever will support.

These syntaxes continue to impose costs on development. Not all related bugs have been fixed, and changes to nearby code do have to take account of this syntax. We have had at least one long-standing (but believed “mostly harmless”, in that a sanity-check fails but surrounding defensive code completely contains the problem) bug involving this syntax, which due to its relative harmlessness has gone unfixed for nearly three years (and, almost as bad, undiscovered for two of them). Recent implementation work on ES5’s strict mode support required adjustments to the area of parsing object literals (for ES5’s strict mode rejection of duplicate property names), adjustments required to work around support for these syntaxes.

In short, TANSTAAFL. We’ve paid a large cost to keep these syntaxes around, and we continue to pay to keep them around — sometimes directly, sometimes indirectly, but unavoidably if support is worthwhile.

Support for all non-ES5 accessor syntaxes has been removed from SpiderMonkey

But for the many reasons previously given, support for these obsolete syntaxes is not worthwhile, so we have removed them from SpiderMonkey. get property funname() { } was an error from the start that no one will miss. SpiderMonkey has recently implemented support for ES5 numeric- and string-literal accessor property names (support for keyword names already exists), so the remaining important use case for property getter: has been eliminated. The getter = and getter function syntaxes never provided extra value, so they too have been removed without qualms.

To give an idea of the complexity eliminated by removing these syntaxes, the patch to remove them added 116 lines of code but removed 313 lines of code. Outside of code changes (that is, adjusting or removing tests which used these features), it added 133 lines but removed 1213 lines. It’s always great deleting code like this. :-)

Updating existing code to adapt to these removals

One nice feature of removing syntax is that the failure mode when that syntax is encountered is blindingly obvious: the script will fail to parse. Parse errors show up in the JavaScript console, so it’s easy to tell when this is the problem; SpiderMonkey’s excellent error messages should point directly at the offending location.

If by chance you do actually use any of these syntaxes, the necessary fixes are simple. Suppose the existence of these helper functions:

function accessorDescriptor(field, fun)
{
  var desc = { enumerable: true, configurable: true };
  desc[field] = fun;
  return desc;
}

function defineGetter(obj, prop, get)
{
  if (Object.defineProperty)
    return Object.defineProperty(obj, prop, accessorDescriptor("get", get));
  if (Object.prototype.__defineGetter__)
    return obj.__defineGetter__(prop, get);

  throw new Error("browser does not support getters");
}

function defineSetter(obj, prop, set)
{
  if (Object.defineProperty)
    return Object.defineProperty(obj, prop, accessorDescriptor("set", set));
  if (Object.prototype.__defineSetter__)
    return obj.__defineSetter__(prop, set);

  throw new Error("browser does not support setters");
}

Here’s how you can update each old syntax to work again:

get property funname() { }
var o = defineGetter({}, "property", function funname() { });
property setter: fun
var o = defineSetter({}, "property", fun);
obj.prop getter = fun
defineGetter(obj, "prop", fun);
setter function prop() { } (when at global scope; otherwise just remove the setter prefix)
defineSetter(obj, "prop", fun);

You can experiment with a version of Firefox with support for these obsolete syntaxes removed by downloading a nightly from nightly.mozilla.org. (Don’t forget to use the profile manager if you want to keep the settings you use with your primary Firefox installation pristine.)

A brief word on __defineGetter__ and __defineSetter__

As you may have noticed, all examples here use Object.defineProperty in preference to either __defineGetter__ or __defineSetter__, using the latter two only as fallback when the former is absent. While many browsers support these methods, not all do. Object.defineProperty is the future, and it is the standard; Microsoft has even gone on the record to say that they will not implement __defineGetter__ or __defineSetter__ in IE given the existence of the standardized method (props to them for that choice, by the way). For greatest forward compatibility with all browsers, you should use Object.defineProperty if it exists, and only fall back to __define{G,S}etter__ if it does not.

In a distant future we would like to remove support for __defineGetter__ and __defineSetter__, after ES5 adoption has taken off, so as not to distract from the standardized support. The less new web developers have to know about legacy extensions superseded by standardized alternatives, the better. This action is at least several years in the future, likely longer; being able to make the change will require preparation and adjustment in anticipation of that time. Given upcoming releases of browsers supporting ES5 functionality, there’s no better time than the present to start gradually, and gracefully, adopting standardized methods over legacy alternatives.

07.04.10

Strange Fruit

(I first heard the song several months back, but the 95th anniversary of Billie Holiday‘s birthday today presented a convenient excuse to prerecord a post for now.)

Disturbing, depressing, haunting:

While it's certainly worthwhile to see Holiday herself singing Strange Fruit, I think I prefer the audio from the studio recording

Via the excellent Night Lights Jazz Program, at around 26:35 (make sure to check out their archives of weekly broadcasts dating back to 2004, some great stuff in the back-episodes I’ve enjoyed). The song later went on to be called the song of the century by Time magazine. According to the broadcast, when Billie Holiday performed Strange Fruit at the Café Society nightclub, it was as her last number of the night; its owner, Barney Josephson, couldn’t imagine her following it with anything else (quite understandably, I think). I’d never heard it before now, and while I can’t quite say I’m glad to have heard it, it was worth hearing. Anyway, something to think about.

(Apologies for disrupting your day if you find you can’t get the song or its topic out of your mind. For some reason, at least for me personally, it feels like historic treatment of racism in the South is rather more clinical and sparse than, say, treatment of the Holocaust during World War II, which is probably why I find the song and lyrics so disturbing — they’re fresh and novel. Emphasis is certainly important concerning history of this nature, but relentless repetition [if nowhere else, I think I got that with respect to Nazi Germany in my high school German classes] desensitizes one to emotional impact. It’s unfortunate we don’t treat topics such as these more carefully — neither excessively nor sparingly, and with the right amount of gravity and eloquence.)

06.04.10

More changes coming to SpiderMonkey: the magical __count__ property is being removed

Tags: , , , , , — Jeff @ 17:17

Meet __count__

SpiderMonkey for some time has included a little-known, little-publicized, and little-used property named __count__ on all objects. This property stored the count of the number of enumerable properties directly on the object. For example,

assertEqual({ 1: 1 }.__count__, 1);
assertEqual([].__count__, 0);
assertEqual([1].__count__, 1);
assertEqual([1, /* hole */, 2, 3].__count__, 3);

It’s sort of a convenient way to check property counts, avoiding a verbose for (var p in o) loop. For example, you could use it to determine how many mappings you had in a hash.

Unfortunately, __count__ has a number of problems.

What’s wrong with __count__

First, and most notably for web developers, __count__ is non-standard. To the best of my knowledge, no other JavaScript engine supports it. Developers must write scripts under the assumption it doesn’t exist, so it provides no brevity bonus. (I recognize extensions and Mozilla-based applications are a special case. For the further reasons below, it’s still worth removing even if some code could assume its existence.)

Second, the special __count__ property contributes to the problem that you can’t actually use an object as a string-value hash. The reason is that you have to be careful that your string-valued keys don’t conflict with special properties, because special properties can’t be overwritten with a custom property. This breaks the nicest feature of using objects for hashes: you can’t just use normal [] property access to set and retrieve mappings. If someone inserts a mapping of, say, "__count__""special", the association with "special" won’t be preserved; obj.__count__ = 5 is actually a no-op. (NB: Even ignoring __count__ other special properties prevent this from working, but we’re slowly working toward getting rid of them. [Some much more slowly than others, I hasten to note! You don’t need to worry about __proto__ being removed any time in the near future, although you should use Object.getPrototypeOf(obj) with a compatibility shim to determine obj‘s prototype in new code.]) A further wrinkle is that __count__ is implemented in such a way that an object literal with "__count__" as a named property functions differently from an object to which the property is later added by assignment:

var o = { __count__: 17 };
assertEqual(o.__count__, 17);

// ...but...
var o2 = {};
o2.__count__ = 17;
assertEqual(o2.__count__, 17); // fails: __count__ is 0

Third, in supporting __count__ we’ve incurred special-case deoptimization code in SpiderMonkey’s script-to-bytecode compiler. This extra complication, for a feature not often used, does nothing for code readability, complexity, or quality.

Fourth, __count__ doesn’t work the way you might think it works: it’s not uniformly fast for all objects. Property access generally has a syntactic assumption of constant-time speediness. This assumption isn’t valid in languages with getters and setters, but since it’s usually the case, it’s not a horribly inaccurate one. Thus, one might expect that evaluating obj.__count__ is an uncomplicated O(1) operation which doesn’t allocate memory and just looks up the size of an idealized hash table. It might be possible to make that true, but in fact it never has been true: generally, computing __count__ is O(n) in the number of properties on the object. Further, because __count__ reuses the same enumeration mechanism as for loops, it usually requires a memory allocation, which can be slow. __count__ has no asymptotic advantage over manual enumeration of the object’s properties.

In sum, __count__ has problems that mean it doesn’t give you much more than a for (var p in o) loop would. If that loop were placed in a function, it would be almost identical in code size to use of the property — and it would have the advantage of being completely cross-browser.

__count__ is being removed

We have removed support for __count__ from SpiderMonkey. As a consequence __count__ will also be removed from the next version of Firefox based on trunk Mozilla code. (And, of course, future versions of other Mozilla-based products like SeaMonkey will pick the change up when they produce releases based on trunk Mozilla code.) For the above reasons __count__ doesn’t make much sense to keep around, and it imposes real development costs. You should have no difficulty updating your code to implement alternative functionality to __count__. Here’s one example of how you might do this:

function count(o)
{
  var n = 0;
  for (var p in o)
    n += Object.prototype.hasOwnProperty.call(o, p);
  return n;
}

assertEqual(count({ 1: 1 }), 1);
assertEqual(count([]), 0);
assertEqual(count([1]), 1);
assertEqual(count([1, /* hole */, 2, 3]), 3);

If you use __count__ and need to test changes to remove that use, you can experiment with a version of Firefox with support for __count__ removed by downloading a nightly from nightly.mozilla.org. (Don’t forget to use the profile manager if you want to keep the settings you use with your primary Firefox installation pristine.)

04.04.10