Configurability of @@toStringTag for Built-ins
The @@toStrngTag mechanism is, by design, unreliable for non-legacy built-ins. TC39 decided that the legacy use of O.p.toString as a normative type test for built-ins was a practice we wanted support moving forward beyond ES5.
Why do you think there should be consistency across built-ins? What about consistency between built-ins and ES defined classes?
Allen Wirfs-Brock wrote:
The @@toStrngTag mechanism is, by design, unreliable for non-legacy built-ins. TC39 decided that the legacy use of O.p.toString as a normative type test for built-ins was a practice we wanted support moving forward beyond ES5.
This led to the further complexity in ES6's O.p.toString of prepending "~" to a legacy builtin name impostors! people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring
It all hangs together but seems a bit much.
Alternative is to make toStringTag non-configurable for all classes.
Why do you think there should be consistency across built-ins? What about consistency between built-ins and ES defined classes?
I suspect people (some of 'em ;-) will want consistent high-integrity toStringTag.
On Dec 16, 2014, at 1:58 PM, Brendan Eich wrote:
It all hangs together but seems a bit much.
We been around this many times and had a TC39 consensus. There is no time to go around this with TC39 again, before the final ES6 draft has to be completed.
Alternative is to make toStringTag non-configurable for all classes.
Do you mean new built-ins or also user defined classes (which don't necessarily even have names). It's also not clear how impostures could be prevented give an open ended set of future built-in and user defined classes.
I suspect people (some of 'em ;-) will want consistent high-integrity toStringTag.
They can make the toStringTags they care about non-configurable at startup, at the same time they capture a reference O.p.toString.
There are many things that could have been locked in in ES6, but we had a consensus that we wouldn't do that beyond making some new properties resistant to accidental change by making them non-writable+configurable.
It should go without saying I'm not proposing an ES6 change. This is all just es-discuss discussion, at most informative for future editions.
Allen Wirfs-Brock wrote:
They can make the toStringTags they care about non-configurable at startup, at the same time they capture a reference O.p.toString.
That's a good point. It helps one part of the equation (unreliability in face of Object.defineProperty), but of course not the other (impostor toStringTag settings on spoofing objects or mocks).
On Dec 16, 2014, at 4:14 PM, Brendan Eich wrote:
It should go without saying I'm not proposing an ES6 change. This is all just es-discuss discussion, at most informative for future editions.
It would be nice if es-discuss post were more explicits about this and discussed them as possible ES7 changes, if for no other reason than then to avoid freaking me out ;-). There are still urgent ES6 problems the pass through here and I have to pick them out of the traffic.
That's a good point. It helps one part of the equation (unreliability in face of Object.defineProperty), but of course not the other (impostor toStringTag settings on spoofing objects or mocks).
If they are specifically concerned about built-ins, almost all of them have methods that do internal brand checks and it in a number of cases those methods can be used as non-distructive tests for those built-in brands. It would be a nice exercise for somebody to go through the built-in and identify for each of them how to perform such brand checks.
In ES6 here is no comparable reliable branding mechanism for user-defined class other than using a WeakMap/Set to register instances.
Allowing configurability of the value of a built-in object's @@toStringTag property has the (likely undesirable) side effect of making calls to Object.prototype.toString.call(o) unreliable.
Illustrated here: twitter.com/caitp88/status/525700685942509569
Repeated here for the purpose of discussion:
Object.prototype.toString.call(new Map()); "[object Map]" Object.defineProperty(Map.prototype, Symbol.toStringTag, { value: "Fish" }); // ... Object.prototype.toString.call(new Map()); "[object Fish]"
While this won't break existing code (see: people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring), there should be consistency across built-ins. I propose we adopt as a rule that the @@toStringTag for all built-ins is always defined as:
{ [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }