Must built-in prototypes also be valid instances? (Was: Why DataView.prototype object's [[Class]] is "Object"?)
allen at wirfs-brock.com
Mon Oct 1 16:50:44 PDT 2012
On Oct 1, 2012, at 3:48 PM, Brendan Eich wrote:
> Allen Wirfs-Brock wrote:
>> Let me try explaining this again,
> No need to rehash.
> Responding to my point about other legacy "tag tests" that are not twiddled with "~" and so are possibly "invalidated" would be helpful. *Why* are the core language names sacrosanct when tag-testing of other class names is also potentially just as important, e.g., for SES?
My main concern isn't SES-like things. It is random general use of Obj.proto.toString to identify instances of built-ins such as Array and Function.
I think we have to support reliable Obj.proto.toString-based tag-test for "Arguments", "Array", "Boolean", "Date", "Error", "Function", "JSON", "Math", "Number", "RegExp", and "String" because those specific values are explicitly defined in the ES5.1 specification and are universally supported by implementations. Assigning one of those tags (via @@toStringTag or any other mechanism) may break existing code.
The only other legacy tag tests presumably are of DOM objects (or other non-standard built-ins). I don't thing we have an obligation to preserve legacy code with such dependencies that isn't already universally interoperable. I would be more concerned about the DOM objects if there had been a history of consistency of tag values among implementations (but we may be racing the WebIDL implementation clock in this regard).
Also as we move into a much larger space of classes and that includes the possibility of self-hosting libraries such as the DOM it is rapidly becoming impractical to guarantee the unique mapping to such toString tags to specific implementations of an abstraction.
So, my position is that we only guarantee the above toString tag tests that are carry overs from ES <= 5.1and that we loudly state Obj.proto.toString can not be used as a reliable nominal type tag for any other objects. We essentially (except for the 11 above cases) let Obj.proto.toString revert to its rightful place as a debugging aid.
>> The little quicks like the "~" prefix and the exception eating are simply what is necessary
> Not so fast there, Tex!
> First, *something* is necessary for preserving certain names from being spoofed and invalidating a tag-test, but we should agree on the names and the reason for spoof-proofing exactly and only that set of names.
Of course, there are other ways of preventing spoofing. The key point is we need to avoid spoofing that interferes with legacy test of the 11 ES5 tags.
> Second, eating exceptions does *not* follow from "what is necessary" even if I agree with your set of names! Eating exceptions is bad on principle. Why do you do it here? A host object might throw on attempt to get a novel property name such as @@toStringTag but is that an actual concern?
Yes, eating exception is a separable issue. But I have thought of it as a compatibility issue. Obj.proto.toString never throws in ES<=5.1. Adding conditions where it does throw seems like a potentially breaking change. For example, an self-host object inspector implementation many not currently be wrapping calls to Obj.proto.toString with an exception handler because it thinks that call never throws.
Once we get beyond using Obj.proto.toString as a nominal type tester, its primary use is going to be as a diagnostic/debugging aid. From that perspective having the tag access throw what is likely to be an uncaught exception seems undesirable. Better to just indicate in the "debug" text that an some unexpected occurred.
> Also, I'm assuming the "???" strings are just place-holders. True?
Sure, it could be any thing, include a description of the exception that occurred.
>> to formalize this extensibility model while still preserving the behavior of existing code that depends upon object.prototype.toString as a reliable mechanism to test for instances of the ES<=5.1 built-ins.
> Adding new internal method calls with novel ids might add new exception throws. That's part of the package deal.
Yes, in general I agree. But given the primarily debugging use of @@toStringTag, an exception seems undesirable. If we were talking about something like @@interator I would agree that eating exceptions would be highly undesirable.
> Implementors control their host objects in general and can tame any that might throw on @@toStringTag [[Get]]. Suppose an implementation has a bug where such a throw happens, for any reason (could be the novel symbol property-name, or could be some other reason). Suppressing prevents anyone (implementor, developer, us) from knowing what is going on.
But we aren't just talking about platform implementors and host objects. This is now an extension point that anyone defining a set of classes might (probably should) use.
> I'm laboring over this because in JS1 I suppressed exceptions trying toString and valueOf and that bit back. [[DefaultValue]] uses ReturnIfAbrupt which propagates the abrupt completion rather than dropping it on the floor.
[[DefaultValue]] must ReturnIfAbrupt because that is what current implementations do. I would guess that where you go bit ij [[DefaultValue]] eating exception from toString/valueOf was in situations where they were actually being over-ridden to provide useful conversion behavior that was buggy. But in this case, we have already bottomed out in Obj.prototype.toString which has been long known to always return a string and never an exception. My trickery was just trying to maintain that postcondition.
Eating tag access exception within Obj.proto.toString probably isn't essential but it still feel slightly more desirable to me than having in throw in these corner cases.
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the es-discuss