Liorean disagrees with the rant I made a fortnight ago. He thinks that Array.prototype
is impolite to muck with and gives a couple reasons why. I understand where he’s coming from, but I’m not quite convinced that the examples he cites are deal‐breakers.
(N.B.: What follows is the opinion of one man. This section is non‐normative.)
The JavaScript for..in
loop is broken. It’s not broken in the scope of what it was designed for, but it’s broken in the way that most people expect it to work.
It’s extremely useful for object introspection, which I’d guess was its original purpose, but its drawbacks are such that it can’t reliably be used for anything else. It enumerates properties that occur anywhere in an object’s inheritance chain, but it does not give script writers any way to hide particular properties from enumeration. (Yes, you can use hasOwnProperty
in your loop. But good luck getting any third‐party scripts you use to do the same.)
This is why we’ve tentatively agreed on Object.prototype
as the no‐fly zone. This is an ugly compromise that makes me queasy, because it takes away a bunch of really cool possibilities, but it’s the best we can do.
Brendan Eich has identified this as one of the weaknesses of JS1 — that sharing namespaces requires “cooperation and benign code.” Of course, as we’re illustrating, each coder has his own definition of benign. Packages are just one of the many ways that JavaScript 2 is supposed to facilitate “programming in the large.”
(Google won’t tell me whether true hashes are planned in JS2, but I desperately hope so. Brendan, care to comment?)
I’m not calling for a moratorium on for..in
. I’m simply saying that anyone who uses for..in
needs to be aware of what she is asking for and what she might receive in return. It’s not JavaScript’s version of foreach
. Anyone who treats it that way is inviting trouble.
Of course, this is really just a philosophy difference: you say extending Array.prototype
is impolite, but I say assuming Array.prototype
hasn’t been extended is naive. Array
isn’t your object any more than it’s mine; it’s a community property, so a script writer needs to know that his array might have more properties than the few he has explicitly set.
I agree with David Lindquist on this one:
[A]s long as we are forbidding things, I would much rather discourage the use of for/in than get rid of the über‐handy Array extensions!
If I had to give up for..in
in order to gain Prototype’s each
method, I’d do so in a heartbeat. The minor hassle of implementing my own hashes would be forgotten in the face of all the keystrokes I’d save. Do you know how happy I am now that every fifth line in my code isn’t for (var i = 0; i < arr.length; i++) {
?
Some people disagree. Some people disagree very loudly. Fine! Our libraries are incompatible because our definitions of benign are incompatible. I’m not trying to convert you; I’m just trying to make you stop calling me a heathen. Use whatever code makes you happy.
I’m not saying that these issues aren’t important, but aren’t there more constructive ways to channel our emotions here? If half a dozen of the world’s foremost JavaScript rockstars walked into a conference room, they’d walk out twenty minutes later with a bulletproof implementation of hashes in only nine lines of code. Why haven’t we done this yet?
Comments
I’ll repeat here what I said to you in an email:
If we can’t extend the Array object then we are effectively writing off IE5.0 which does not support
push/pop
. That seems a trifle unfair to 1% of web users. This is throwing out the baby with the bath water.On that note, if
HTMLElement.prototype
were mutable in IE, then it’d be a lot easier to write cross-browser JavaScript without abstraction.I have a lengthy wishlist for IE8, but this is at the top, because mutable prototypes allow us to fix things ourselves.
Amen.
Prototypes each internally uses for .. in too, obviously, and deliberatly prevents all functions from being enumerated.
See my proposed patch, so you can mark functions for enumeration, making prototype hashes almost complete:
http://dev.rubyonrails.org/ticket/4689
You’re right that for-in was invented for introspection, although I implemented and wanted to standardize the behavior still shown by SpiderMonkey: properties are enumerated in the order in which they were created. This was shot down during the standardization of ECMAScript, with at least MS’s rep objecting.
For ES4, we will extend Object.prototype.propertyIsEnumerable to take a second argument after the property id, which if Boolean will set or clear the enumerable attribute (ECMA-262 uses a DontEnum inverted bit).
Better, we will make for-in loops work sanely when the object on the right of in is an iterator (has a certain structural type). This is a backward compatible extension that enables array comprehensions, by allowing the iterator to determine the values returned, without unwanted prototype chain enumeration, and without converting keys to strings.
See http://developer.mozilla.org/es4/ for a rough export of the ECMA TG1 dokuwiki, including a quite rough ES4 spec.
/be
Thanks, Brendan. I’ve been gazing at ES4 documents for a week or so and have realized that my proficiency in JavaScript is insufficient preparation for the high-level dialogue that occurs during spec-writing. I’m on the ES4 mailing list and expect to be an enthusiastic spectator in the proceedings.