Number.prototype not being an instance breaks the web, too

# Andreas Rossberg (4 years ago)

V8 just rolled a change into Canary yesterday that implements the new ES6 semantics for Number.prototype (and Boolean.prototype) being ordinary objects. Unfortunately, that seems to break the web. In particular jsfiddle.net/#run fails to load now.

What I see happening on that page is a TypeError "Number.prototype.valueOf is not generic" being thrown in this function (probably part of moo tools):

Number.prototype.$family = function(){
return isFinite(this) ? 'number' : 'null';
}.hide();

after being invoked on Number.prototype.

AFAICS, that leaves only one option: backing out of this spec change.

(See code.google.com/p/chromium/issues/detail?id=476437 for the bug.)

# Mark S. Miller (4 years ago)

I agree. With Number.prototype joining Array.prototype and Function .prototype on the dark side, we should ask which others should too. When it was only Function.prototype and Array.prototype, principle of least surprise (POLS) had us keep the list as small as possible -- until we had precisely this kind of evidence of incompatibility. From a security pov, the important ones not to revert are those carrying mutable state not locked down by Object.freeze. In ES5 this was only Date.prototype. Of the ES5 builtins in ES6, this now includes RegExp.prototype because of RegExp.prototype.compile. (Because of de facto stack magic, this might include Error.prototype as well.) Fotunately, there is still no evidence that we need to corrupt these as well.

OTOH, POLS still says that almost everything should not go to the dark side, for consistency with ES6 classes. So the precise line becomes a matter of taste. I propose that the co-corrupted list be

Function.prototype
Array.prototype
Number.prototype
Boolean.prototype   // No incompat data. Only POLS
String.prototype       // No incompat data. Only POLS

since Number, Boolean, and String are the ordinary ES5 wrappers of primitive data values.

For builtins that are new with ES6, clearly there's no compat issue. And both security and consistency with ES6 classes argue in general for not corrupting new things. But POLS should put very little weight on the ES5 vs ES6 difference since post ES6 programmers will just see all of this as JS.

Given that, I could argue Symbol.prototype either way, since Symbol is kinda another wrapper of a primitive type. But I prefer not. I think we should keep the list to those 5.

Allen, process-wise, is this too late for ES6? If there's any way this fix can go in ES6, it should. Otherwise, it should become the first member of ES6 errata.

All that said, I do find corrupting only Number.prototype to be plausible. I would not mind if we decided not to spread the corruption even to Boolean .prototype and String.prototype. If we have to do a last minute as-small-as-possible change to the spec, to get it into ES6, this might be best.

# Mark S. Miller (4 years ago)

Hold on. I may have reacted too quickly. If it is only jsfiddle, since this is an online service rather than a widely copied library, they could just fix it. OTOH, if it really is a mootools issue, then yes, we really do need to change the spec. (History: Facebook fixed JSON incompatibility. ES5 fixed Object.prototype.toString.call(null) incompat with jQuery.)

# Allen Wirfs-Brock (4 years ago)

On Apr 13, 2015, at 8:26 AM, Mark S. Miller wrote:

...

Allen, process-wise, is this too late for ES6? If there's any way this fix can go in ES6, it should. Otherwise, it should become the first member of ES6 errata.

yes, no

I have to submit the final version for distribution to the GA today and I'm not gong to make any rash changes in this area.

Note there are other approaches to "fixing" this moo tools issue.

For example, Number.prototype.valueOf, instead of throwing if its this value does not have a [[NumberData]] internal slot could perform the default valueOf behavior.

# Mark S. Miller (4 years ago)

Excellent! +1

# Mathias Bynens (4 years ago)

CCing Piotr.

# Jordan Harband (4 years ago)

Please note that the @@toStringTag changes mean that we do need to always have a Number.prototype method that throws when the value does not have a [[NumberData]] internal slot - I'm using Number#toString for that right now, but others may now be relying on the throw behavior of `Number#valueOf.

# Mark S. Miller (4 years ago)

Wow, awesome catch!

Even though I recently implemented codereview.appspot.com/198470043 , I completely missed that.

To see Caja's current set of dependencies: code.google.com/p/google-caja/source/browse/trunk/src/com/google/caja/ses/repairES5.js#579 They are:

Date.prototype.getDay
(Number,Boolean,String).prototype.toString
RegExpr.prototype.exec
WeakMap.prototype.get

If any of these stop throwing, for Caja and SES, that would be a breaking change.

Thanks for noticing this!