using Private name objects for declarative property definition.
brendan at mozilla.com
Tue Jul 12 11:08:04 PDT 2011
Allen, thanks for replying -- I ran out of time this morning. A few comments on top of yours.
On Jul 12, 2011, at 10:18 AM, Allen Wirfs-Brock wrote:
>> I think an efficient implementation of names in something like V8 will
>> probably want to assign different internal type tags to them either
>> way. Otherwise, we'll need extra tests for each property access, and
>> cannot specialise as effectively.
> Isn't that pretty much a wash either way
Not only that (I argued in my reply), but engines do already tag identifier types. Indexing does not use strings "0", "1", etc., even interned strings, in engines that aspire to be fast. Such (interned) strings must of course be observably equivalent to 0, 1, etc. when used as indexes and preserved as type-tagged integer domain property identifiers.
>> I meant the [[Class]] property (I guess that's what you are referring
>> to as well). Not sure what you mean when you say it is
>> user-extensible, though. Is it in some implementations? (I'm aware of
>> the somewhat scary note on p.32 of the spec.) Or are you just
>> referring to the toString method?
> Because Table 8 says all objects (including host objects) have a string valued [[Class]] property, some people and third party specifications (and perhaps some implementations) have assumed that [[Class]] is an specified extension mechanism for Object.prototype.toString.
> To eliminate any such confusion, in the initial draft for the 6th edition spec. I have eliminated [[Class]] and replaced it with non-parameterized object brands using distinct internal properties. I will make that draft available within the next 24 hours.
Just to amplify Allen's reply, we are working on dom.js (https://github.com/andreasgal/dom.js), the self-hosted DOM. Per its specs, it must be able in some future JS edition to configure the "class name" reported by Object.prototype.toString.call(x, 8, -1).
>> 1. We seem to have (at least) a two-level nominal "type" system: the
>> first level is what is returned by typeof, the second refines the
>> object type and is hidden in the [[Class]] property (and then there is
>> the oddball "function" type, but let's ignore that).
> You can certainly read it that way.
> The real nominal types of ECMAScript are defined in clause 8. Only the "ECMAScript language types" subset are exposed to ECMAScript programmers. The "specification types" subset are just that, specification devices.
The typeof distinction is among primitive types with by-value semantics (null, undefined, boolean, number, string) and object, which as discussed recently has by-reference semantics, observable because objects are in general mutable.
Among the objects, there are many and non-hierarchically-related classification schemes, as Allen reminds us (worth doing to avoid making brittle, crappy, tyrannical nominal hierarchies :-/).
There isn't much "nominal" here in an untyped language. Perhaps we should use "branding" or "trademarking", but when I use "nominal" in connection with JS I mean the same thing: certain built-ins have internal [[Class]] properties which not only contribute to Object.prototype.toString's result, the [[Class]] values are checked aggressively in built-in methods of these objects, such that the methods cannot in general be invoked on objects with other [[Class]] values.
In engine implementations, C++ nominal types are often used, but the JS dispatching machinery does not reflect via C++ RTTI or any such thing. Instead, something corresponding to [[Class]] is compared to a known singleton, to enforce that these non-generic methods are called on the "correct type of |this|".
To sum up, typeof is for value or primitive vs. object type identification. When typeof x === "object", x may then be classified in many ways. As a rule, and I believe the committee agrees on this, we wish built-ins to be generic where practical for implementations to unify representations so as to avoid the [[Class]]-equivalent nominal type tag, AKA brand or trademark, test.
A proposal for Harmony gets into surfacing branding in the language:
This didn't make ES.next.
(To repeat a minor comment I gave at the May TC39 meeting, prefigured above, I hope we can try to use one word, ideally as short as "brand" or "branding", for this "nominal type tag" idea.)
>> Is it the
>> intention that all "type testing" predicates like isArray, isName,
>> isGenerator will essentially expose the [[Class]] property?
> Absolutely not. But note that that these are not "type testing" in the sense that ES uses the work "type". They discriminate different kinds (categorizations) of objects but ES does not define these as types. This is not an unusual dichotomy. For example, if you define Integer to be a type, what do you consider odd integers to be? Another layer of typing or just a further subcategorization of the member of the Integer type.
However, as my discussion with Allen brought out (I hope!), the three predicates Andreas mentions, isName, isGenerator, and isArray, are all testing "brands".
Sometimes, and I recall agreeing with MarkM on this in 2008 at the July Oslo "Harmony" TC39 meeting, nominal tag testing is critical for, e.g., a security architecture. It is in the DOM, although we've argued about whether or how much is truly needed. It's a minority use-case, and actually more important IMHO (this was Mark's point too, I think) to provide to users of the language than to reserve as magic that only TC39 can burn into specifications.
>> 2. If there are exceptions to this, why? Would it make sense to clean
>> this up? (I saw Allen's cleanup strawman, but it seems to be going the
>> opposite direction, and I'm not quite sure what it's trying to achieve
> see the associated google doc: https://docs.google.com/document/d/1sSUtri6joyOOh23nVDfMbs1wDS7iDMDUFVVeHeRdSIw/edit?hl=en_US&authkey=CI-FopgC
> [[Class]] has caused all sorts of confusion in the realm of host objects. It's use in the spec. has also resulted in some unnecessary over specification that gets in the way extensibility.
>> 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.
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the es-discuss