using Private name objects for declarative property definition.
brendan at mozilla.com
Tue Jul 12 11:21:16 PDT 2011
On Jul 12, 2011, at 11:08 AM, Brendan Eich wrote:
>>> 5. What are the conventions by which the library distinguishes between
>>> "regular" object properties and operations, and meta (reflective)
>>> ones? It seems to me that part of the confusion(?) in the discussion
>>> is that the current design makes no real distinction. I think it is
>>> important, though, since e.g. proxies should be able to trap regular
>>> operations, but not reflective ones (otherwise, e.g. isProxy wouldn't
>>> make sense). Also, modern reflective patterns like mirrors make the
>>> point that no reflective method should be on the reflected object
>> This is what we are in the process of sorting out. The ES spec. (and language) wasn't originally designed from that perspective but I think we can move it there.
> Definitely! I was in a big rush. I recall putting in primitive types (something I've repented at leisure) for two reasons: (1) be like Java (this wasn't just superficial, we were planning the JS/Java bridge, LiveConnect, even from the start in 1995); (2) ease of implementation (arguably I was biasing toward a certain kind of implementation, but it was what I knew how to do fast: fat discriminated union value types, hardcoded arithmetic for the NUMBER discriminant).
> For functions, I made a distinct typeof result so that users could determine callability (remember, there was no try/catch/finally in JS1 and anyway, try around a call attempt is too heavyweight).
> Among objects apart from functions, I created the prototype.constructor back-link but otherwise left it up to object implementors to come up with classification schemes.
A bit more on the history of reflective facilities added at the base layer:
For JS1 there was zero time to do proper mirrors-style reflective APIs. Economy of implementation and expression, plus the utility of objects as hashes, led me to make o[e] evaluate e into a result and equate it to a string property name. Even in the first implementation, which had some goofy bugs, I int-specialized for speed. From AWK (capitalized like a fanboy, after its creators' surname initials) I copied for-in as the matching way of enumerating the keys in the object-as-hash.
So at base level, one can reflect on what other languages do not disclose without mirrors: the names of properties and, given any expression, the value of a property named by the string conversion of the result of evaluating that expression.
ES3 added "in", "instanceof" (we've talked about how this went wrong in the face of multiple globals), and a paltry (six, IIRC) Object.prototype reflective methods, some of which seem misdesigned (e.g. propertyIsEnumerable does not have "own" in its name but does not look up the proto chain). This was just shortest-path evolution in TC39 TG1, mostly, although I seem to recall prototyping "in" in SpiderMonkey before ES3 was far along.
Allen's work with mirrors shows how rich and multifarious the reflection API world can be. This is good work and we need more of it. I don't think we should prematurely standardize mirror-style reflective APIs. We do need to correct course on reflective and other API design path missteps where we can.
Waldemar made this point about standards processes: they can cycle faster but create path dependencies and enshrine mistakes, painting the language into a corner. Cycling too slow is bad too, obviously -- we have been there and done that (it's why we at Mozilla added so many things like getters and setters, __proto__, Array extras back during the dark ages -- we had no choice with a monopoly shutdown of the standards process, and taking that lying down is not "good" in itself or obviously better than making de-facto standards).
Cycling at a pace that fits the Ecma->ISO protocols can work but leaves us with mistakes small (we hope) enough to live with, but sometimes worth fixing (we should consider each such potential mistake). I know Allen feels this regarding Object.create, specifically the property descriptor attribute defaults and consequent verbosity when describing typical properties. I feel it of course over all the mistakes in most of the language that I've created or had a hand in (or where I took time off to found mozilla.org, and did not help ES3). I'm not guilty at this advanced age, just resolved to fix what can be fixed.
Mistakes happen, we need to be careful -- but we aren't going to do anyone any favors by sitting and thinking on how to achieve perfection -- so we ought to make corrections as we go. Backward compatibility then means some redundancy over time. There are much worse problems to have.
More information about the es-discuss