primitive boxing in instanceof due to Symbol.hasInstance
people.mozilla.org/~jorendorff/es6-draft.html#sec-instanceofoperator calls GetMethod on C without checking if it is an Object, this means
1 instanceof Foo
could be affected by mutatingNumber.prototype[Symbol.hasInstance]
.
I assume you mean "without checking if O is an object"
I am assuming this is unintended?
IIUC the point of @@hasInstance is to allow the programmer to define completely arbitrary semantics for "instanceof" when applied to "C", even if C is a built-in. Do you see a problem with this behavior?
Yes, with to O being an Object.
This seems a bit strange to me since things like:
Number.prototype.toString = function () {return 'overriden';}
(1)+'' // "1"
String(1) // "1"
(1).toString() // "overriden"
Implicit string coercion does not box the object. String constructor does not box the object.
Only the .
operator which requires an Object boxes the object.
instanceof
works on non-objects but I think is the only case of an
operator working on both primitives and objects causing boxing.
Is there a reason constructors could/should be allowed to override
instanceof
for primitives? This just seems odd to have this cause boxing
while 1 instanceof Number
is false
.
point of views I guess, you could fix forever the inconsistency via
Number.prototype[Symbol.hasInstance] = function () {
return typeof this.valueOf() === 'number';
};
and fix String, Boolean, Symbol too (why not) and whatever else.
instanceof
is the new typeof
^_^ (naa, just joking)
Best
Well this also has slightly odd behavior since the Object operation will fail for OrdinaryHastInstance if for primitives people.mozilla.org/~jorendorff/es6-draft.html#sec
so Object(unknown) instanceof Number
it is then ¯_(ツ)_/¯
Would not work since @@hasInstance takes priority over OrdinaryHasInstance and would box it.
On Jun 15, 2015, at 10:06 AM, Bradley Meck wrote:
Kyle Simpson caused the discovery of this oddity :
people.mozilla.org/~jorendorff/es6-draft.html#sec-instanceofoperator calls GetMethod on C without checking if it is an Object, this means
1 instanceof Foo
could be affected by mutatingNumber.prototype[Symbol.hasInstance]
.I am assuming this is unintended?
No, it is exactly as intended:
GetMethod users GetV people.mozilla.org/~jorendorff/es6-draft.html#sec-getv which handles accessing properties for primitives. For primitive values, it uses the built-in wrapper prototype to lookup properties, but it does not actually create a boxed primitive value.
this
object boxing is a characteristic of the callee, not the caller. Non-srict functions box primitive this values
that are passed to them, strict mode functions do not.
This is all the standard method invocation behavior, and the instanceof
operator just does a normal method invocation if it finds a Symbol.hasInstance
method. Because Function.prototype implements Symbol.hasInstacce
all function haves the default legacy behavior when appearing right-side operand of instanceof
But instanceof
does not depend upon the existence of a a Symbol.hasInstance
method. It falls back to performing the default (legacy) instanceof check if a callable hasInstance
property value is not found.
But, back to the original question: Exactly what do you expect to be boxed for 1 instance of Foo
? The C
that GetMethod is applied to is Foo
which would normally be a constructor or some other "type-like" object implements. It could be a primitive numeric value (eg, 5 instanceof 4
) which will cause the fallback to be taken using Number.prototype has a Symbol.hasInstance
callable property. But, even if it does why would you expect anything to box?
On the surface O instanceof C
boxes C
, but when using GetMethod
O
turns O into an Object. This means instanceof
is temporarily turning O
into an Object.
For primitives, all the operators in JS have been unable to be altered
until this was pointed out. 1 instanceof C
is able to be changed by
mutating %NumberPrototype% , "" instanceof C
by mutating
%StringPrototype% , etc.
Compared to other operators this is new and a bit surprising that primitive behaviors are mutable.
I would expect this behavior by boxing primitives via Object(primitive) instanceof C
but not for primitives.
On Jun 15, 2015, at 9:21 PM, Bradley Meck wrote:
On the surface
O instanceof C
boxesC
, but when usingGetMethod
O turns O into an Object. This meansinstanceof
is temporarily turning O into an Object.
Read the spec people.mozilla.org/~jorendorff/es6-draft.html#sec-relational-operators-runtime-semantics-evaluation
o instanceof C
performs InstanceOfOperator(O,C) which performs GetMethod(C, @@hasInstance)
so GetMethod doesn't even see the value of o
.
For primitives, all the operators in JS have been unable to be altered until this was pointed out.
1 instanceof C
is able to be changed by mutating %NumberPrototype% ,"" instanceof C
by mutating %StringPrototype% , etc.
In ES6 certain operations (instanceof and the internal ToPrimitive which is used by several operator) were made extensible because Host and built-in objects have always been able to extend their semantics. For example, WebIDL has it's own unique definition of instanceof that it uses for DOM objects. Extensibility of these operations via JS code is necessary in order to enable such libraries to be directly self-hosted using JS code.
Compared to other operators this is new and a bit surprising that primitive behaviors are mutable.
I would expect this behavior by boxing primitives via
Object(primitive) instanceof C
but not for primitives.
O is the argument to hasInstance methods. JS has never auto-boxed primitive argument values.
You are correct, it is not the primitive being boxed, but the primitive being passed into @@hasInstance.
Still consider it very strange that I can change if 1 instanceof Number
but if that was intentional /shrug. Typeof I guess will be the safe way to
detect things.
On Jun 16, 2015, at 6:04 AM, Bradley Meck wrote:
You are correct, it is not the primitive being boxed, but the primitive being passed into @@hasInstance.
people.mozilla.org/~jorendorff/es6-draft.html#sec-instanceofoperator doesn't box O passed into the the @@hasInstance method. See step 4.a. Are you using a transpiler? Maybe it is buggy.
Kyle Simpson caused the discovery of this oddity :
people.mozilla.org/~jorendorff/es6-draft.html#sec-instanceofoperator calls GetMethod on C without checking if it is an Object, this means
1 instanceof Foo
could be affected by mutatingNumber.prototype[Symbol.hasInstance]
.I am assuming this is unintended?