Re: Implementing an identical JSON.stringify

2018-08-05 Thread Allen Wirfs-Brock


> On Aug 4, 2018, at 9:47 PM, Darien Valentine  > wrote:
> 
> > I guess what confused me is that it would detect a [[NumberData]] internal 
> > slot, but instead of unboxing to that value it tries to ducktype call 
> > .valueOf on the object. So the presence of [[NumberData]] changes the 
> > behavior even if it does not actually use this value.

Fundamentally, the tests are trying to determine which values are supposed to 
be serialized as JSON primitive values and which need to be serialized as JSON 
objects (or arrays). The assumption in JSON stingify is that JS wrapper objects 
for numbers, strings, and booleans should be serialized as primitive values.

The ES JSON functions were based upon Crockford's original JSON 2 API and his 
implementation of it as it existed in mid 2008 
(https://web.archive.org/web/20090213004934/http://www.json.org/json2.js 
). 
Crockford, in his design,  made the decisions that the wrapper objects should 
serialize as primitives. In his implementation he accomplished that adding 
toJSON methods to the prototypes of Number, String, and Boolean. The body of 
those methods were: return this.valueOf();

In ES5, we wanted to avoid having to add a bunch of toJSON methods to the 
builtins (Date was the exception). So, we needed a cross-realm way to test for 
those primitive wrapper values. In ES1-5 the way to do that was to test the  
value of the [[Class]] internal property which was set for all built-in 
objects. If a Number or Stream wrapper [[Class]] value was detected, we did an 
internal ToNumber or ToString to get the primitive value. This is equivalent to 
what the built-in valueOf methods do. 

In ES6, [[Class]] was eliminated as a specification device because it was 
confusing and starting to be misused. I realized that (for specification 
purposes) we could describe the equivalent test as a test for an internal slot 
that was unique to each kind of wrapper.  So, the [[Class]] test was replaced 
with tests for [[NumberData]], [[StringDate]], and [[BooleanData]]. That 
specification change should not be observable to JS code.  I didn’t change the 
ToNumber and ToString calls because that would have been a potentially 
observable change.

> 
> This surprised me too initially, but I think we can infer a rationale if we 
> read between the lines a bit. A similar pattern appears in the JSON stringify 
> algorithm itself (as opposed to the SerializeJSONProperty algorithm) when 
> interpreting the "space" argument. So it might seem to be that it’s a 
> peculiarity of how JSON-related operations are defined — but I don’t think 
> that’s the pattern. What these two cases have in common is that either a 
> numeric value or a string value would be valid: neither hint would be more 
> correct. In the case of SerializeJSONProperty, this is because both string 
> values and numeric values are valid JSON values; in the case of stringify’s 
> space argument, it’s because this is overloaded to either specify a number of 
> spaces or a whitespace string. In the absence of a reason to weight one 
> to-primitive operation over another, it sniffs for the singular unambiguous 
> clue about type that’s really available, the slot.

Yes, this is correct.  It is because of overload resolution. Crockford’s 
original implementation only recognized primitive Numbers or Strings as the 3rd 
argument. Any object, including wrapper objects, passed as the 3rd argument 
were ignored. I thought that wrapper objects should also be accepted so I 
introduced the sequence you see in the spec. which is similar to what was also 
done in SerializeJSONProperty.

In retrospect is might have been better to have followed Crockford’s example. 
It’s very unlike that a wrapper object would ever be passed as that argument.  
It’s probably more likely that an object with a bespoke valueOf or toString 
might be passed and the algorithm, as specified, ignores such objects..

Allen


> 
> Why doesn’t it then just use the slot value directly? Because this would 
> depart from expectations about the @@toPrimitive / toValue / toString 
> contract that is honored everywhere else, I believe.
> 
> On Sun, Aug 5, 2018 at 12:30 AM Michael Theriot 
> mailto:michael.lee.ther...@gmail.com>> wrote:
> Regarding cases like Reflect.construct(Number, [], String), the reason this 
> throws is because the ToNumber algorithm calls ToPrimitive if its operand is 
> an object. This in turn will call String.prototype.valueOf on the object 
> which does not have [[StringData]]. There’s nothing funny going on, it’s just 
> a weird effect in aggregate. You would just need to implement all the steps 
> here — internal ops like ToNumber, ToPrimitive, etc. It’s not that it 
> "considers type", but rather that these algorithms will call methods by 
> specific names on objects they receive. String.prototype and Object.prototype 
> both implement "valueO

Re: `ToNumber` and `ToString` invoking `toString`/`valueOf` for number/string objects? (Was: Re: Re: Implementing an identical JSON.stringify)

2018-08-04 Thread Jordan Harband
My assumption is legacy behavior - ie, that's what browsers did, so it had
to be codified in the spec.

On Sat, Aug 4, 2018 at 10:20 PM, Isiah Meadows 
wrote:

> This makes me wonder: for objects with [[NumberData]] and
> [[StringData]], why do they call `valueOf`/`toString`/@@toPrimitive to
> coerce them instead of simply accessing the boxed data directly? It
> seems like a pointless waste to check.
>
> -
>
> Isiah Meadows
> cont...@isiahmeadows.com
> www.isiahmeadows.com
>
>
> On Sun, Aug 5, 2018 at 12:30 AM, Michael Theriot
>  wrote:
> >> Regarding cases like Reflect.construct(Number, [], String), the reason
> >> this throws is because the ToNumber algorithm calls ToPrimitive if its
> >> operand is an object. This in turn will call String.prototype.valueOf
> on the
> >> object which does not have [[StringData]]. There’s nothing funny going
> on,
> >> it’s just a weird effect in aggregate. You would just need to implement
> all
> >> the steps here — internal ops like ToNumber, ToPrimitive, etc. It’s not
> that
> >> it "considers type", but rather that these algorithms will call methods
> by
> >> specific names on objects they receive. String.prototype and
> >> Object.prototype both implement "valueOf", but only the former will
> fail the
> >> slot check.
> >
> >
> > Thanks for demystifying this. I never realized it was just ducktyping
> > .valueOf on the object.
> >
> > ```js
> > Number.prototype.valueOf = () => 0;
> >
> > JSON.stringify(1); // 1
> > JSON.stringify(new Number(1)); // 0
> > ```
> >
> > I guess what confused me is that it would detect a [[NumberData]]
> internal
> > slot, but instead of unboxing to that value it tries to ducktype call
> > .valueOf on the object. So the presence of [[NumberData]] changes the
> > behavior even if it does not actually use this value.
> >
> > On Sat, Aug 4, 2018 at 10:14 PM Darien Valentine 
> > wrote:
> >>
> >> Is this a question about how/if one could replicate its behavior in
> theory
> >> from ES code, or are you suggesting a change to the existing behavior
> for
> >> these exotic cases?
> >>
> >> Assuming the former:
> >>
> >> The relevant steps are
> >> [here](https://tc39.github.io/ecma262/#sec-serializejsonproperty). The
> >> `instanceof` a value isn’t significant in this algorithm, just its
> slots (if
> >> it is an object) or its primitive type. So one can handle number and
> string
> >> by leveraging branded checks as you’ve shown — nothing more is needed
> than
> >> branded methods and typeof to manage that one.
> >>
> >> However it is ultimately not possible to replicate because there is no
> >> possible brand test for [[BooleanData]].
> >> ___
> >> es-discuss mailing list
> >> es-discuss@mozilla.org
> >> https://mail.mozilla.org/listinfo/es-discuss
> >
> >
> > ___
> > es-discuss mailing list
> > es-discuss@mozilla.org
> > https://mail.mozilla.org/listinfo/es-discuss
> >
>
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


`ToNumber` and `ToString` invoking `toString`/`valueOf` for number/string objects? (Was: Re: Re: Implementing an identical JSON.stringify)

2018-08-04 Thread Isiah Meadows
This makes me wonder: for objects with [[NumberData]] and
[[StringData]], why do they call `valueOf`/`toString`/@@toPrimitive to
coerce them instead of simply accessing the boxed data directly? It
seems like a pointless waste to check.

-

Isiah Meadows
cont...@isiahmeadows.com
www.isiahmeadows.com


On Sun, Aug 5, 2018 at 12:30 AM, Michael Theriot
 wrote:
>> Regarding cases like Reflect.construct(Number, [], String), the reason
>> this throws is because the ToNumber algorithm calls ToPrimitive if its
>> operand is an object. This in turn will call String.prototype.valueOf on the
>> object which does not have [[StringData]]. There’s nothing funny going on,
>> it’s just a weird effect in aggregate. You would just need to implement all
>> the steps here — internal ops like ToNumber, ToPrimitive, etc. It’s not that
>> it "considers type", but rather that these algorithms will call methods by
>> specific names on objects they receive. String.prototype and
>> Object.prototype both implement "valueOf", but only the former will fail the
>> slot check.
>
>
> Thanks for demystifying this. I never realized it was just ducktyping
> .valueOf on the object.
>
> ```js
> Number.prototype.valueOf = () => 0;
>
> JSON.stringify(1); // 1
> JSON.stringify(new Number(1)); // 0
> ```
>
> I guess what confused me is that it would detect a [[NumberData]] internal
> slot, but instead of unboxing to that value it tries to ducktype call
> .valueOf on the object. So the presence of [[NumberData]] changes the
> behavior even if it does not actually use this value.
>
> On Sat, Aug 4, 2018 at 10:14 PM Darien Valentine 
> wrote:
>>
>> Is this a question about how/if one could replicate its behavior in theory
>> from ES code, or are you suggesting a change to the existing behavior for
>> these exotic cases?
>>
>> Assuming the former:
>>
>> The relevant steps are
>> [here](https://tc39.github.io/ecma262/#sec-serializejsonproperty). The
>> `instanceof` a value isn’t significant in this algorithm, just its slots (if
>> it is an object) or its primitive type. So one can handle number and string
>> by leveraging branded checks as you’ve shown — nothing more is needed than
>> branded methods and typeof to manage that one.
>>
>> However it is ultimately not possible to replicate because there is no
>> possible brand test for [[BooleanData]].
>> ___
>> es-discuss mailing list
>> es-discuss@mozilla.org
>> https://mail.mozilla.org/listinfo/es-discuss
>
>
> ___
> es-discuss mailing list
> es-discuss@mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Re: Implementing an identical JSON.stringify

2018-08-04 Thread Darien Valentine
> I guess what confused me is that it would detect a [[NumberData]]
internal slot, but instead of unboxing to that value it tries to ducktype
call .valueOf on the object. So the presence of [[NumberData]] changes the
behavior even if it does not actually use this value.

This surprised me too initially, but I think we can infer a rationale if we
read between the lines a bit. A similar pattern appears in the JSON
stringify algorithm itself (as opposed to the SerializeJSONProperty
algorithm) when interpreting the "space" argument. So it might seem to be
that it’s a peculiarity of how JSON-related operations are defined — but I
don’t think that’s the pattern. What these two cases have in common is that
either a numeric value or a string value would be valid: neither hint would
be more correct. In the case of SerializeJSONProperty, this is because both
string values and numeric values are valid JSON values; in the case of
stringify’s space argument, it’s because this is overloaded to either
specify a number of spaces or a whitespace string. In the absence of a
reason to weight one to-primitive operation over another, it sniffs for the
singular unambiguous clue about type that’s really available, the slot.

Why doesn’t it then just use the slot value directly? Because this would
depart from expectations about the @@toPrimitive / toValue / toString
contract that is honored everywhere else, I believe.

On Sun, Aug 5, 2018 at 12:30 AM Michael Theriot <
michael.lee.ther...@gmail.com> wrote:

> Regarding cases like Reflect.construct(Number, [], String), the reason
>> this throws is because the ToNumber algorithm calls ToPrimitive if its
>> operand is an object. This in turn will call String.prototype.valueOf on
>> the object which does not have [[StringData]]. There’s nothing funny going
>> on, it’s just a weird effect in aggregate. You would just need to implement
>> all the steps here — internal ops like ToNumber, ToPrimitive, etc. It’s not
>> that it "considers type", but rather that these algorithms will call
>> methods by specific names on objects they receive. String.prototype and
>> Object.prototype both implement "valueOf", but only the former will fail
>> the slot check.
>>
>
> Thanks for demystifying this. I never realized it was just ducktyping
> .valueOf on the object.
>
> ```js
> Number.prototype.valueOf = () => 0;
>
> JSON.stringify(1); // 1
> JSON.stringify(new Number(1)); // 0
> ```
>
> I guess what confused me is that it would detect a [[NumberData]] internal
> slot, but instead of unboxing to that value it tries to ducktype call
> .valueOf on the object. So the presence of [[NumberData]] changes the
> behavior even if it does not actually use this value.
>
> On Sat, Aug 4, 2018 at 10:14 PM Darien Valentine 
> wrote:
>
>> Is this a question about how/if one could replicate its behavior in
>> theory from ES code, or are you suggesting a change to the existing
>> behavior for these exotic cases?
>>
>> Assuming the former:
>>
>> The relevant steps are [here](
>> https://tc39.github.io/ecma262/#sec-serializejsonproperty). The
>> `instanceof` a value isn’t significant in this algorithm, just its slots
>> (if it is an object) or its primitive type. So one can handle number and
>> string by leveraging branded checks as you’ve shown — nothing more is
>> needed than branded methods and typeof to manage that one.
>>
>> However it is ultimately not possible to replicate because there is no
>> possible brand test for [[BooleanData]].
>> ___
>> es-discuss mailing list
>> es-discuss@mozilla.org
>> https://mail.mozilla.org/listinfo/es-discuss
>>
>
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Re: Implementing an identical JSON.stringify

2018-08-04 Thread Michael Theriot
>
> Regarding cases like Reflect.construct(Number, [], String), the reason
> this throws is because the ToNumber algorithm calls ToPrimitive if its
> operand is an object. This in turn will call String.prototype.valueOf on
> the object which does not have [[StringData]]. There’s nothing funny going
> on, it’s just a weird effect in aggregate. You would just need to implement
> all the steps here — internal ops like ToNumber, ToPrimitive, etc. It’s not
> that it "considers type", but rather that these algorithms will call
> methods by specific names on objects they receive. String.prototype and
> Object.prototype both implement "valueOf", but only the former will fail
> the slot check.
>

Thanks for demystifying this. I never realized it was just ducktyping
.valueOf on the object.

```js
Number.prototype.valueOf = () => 0;

JSON.stringify(1); // 1
JSON.stringify(new Number(1)); // 0
```

I guess what confused me is that it would detect a [[NumberData]] internal
slot, but instead of unboxing to that value it tries to ducktype call
.valueOf on the object. So the presence of [[NumberData]] changes the
behavior even if it does not actually use this value.

On Sat, Aug 4, 2018 at 10:14 PM Darien Valentine 
wrote:

> Is this a question about how/if one could replicate its behavior in theory
> from ES code, or are you suggesting a change to the existing behavior for
> these exotic cases?
>
> Assuming the former:
>
> The relevant steps are [here](
> https://tc39.github.io/ecma262/#sec-serializejsonproperty). The
> `instanceof` a value isn’t significant in this algorithm, just its slots
> (if it is an object) or its primitive type. So one can handle number and
> string by leveraging branded checks as you’ve shown — nothing more is
> needed than branded methods and typeof to manage that one.
>
> However it is ultimately not possible to replicate because there is no
> possible brand test for [[BooleanData]].
> ___
> es-discuss mailing list
> es-discuss@mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Implementing an identical JSON.stringify

2018-08-04 Thread Isiah Meadows
It's very subtle, but no, that's correct per spec, and any engine that
doesn't do that is buggy. When `JSON.stringify` is invoked on a
number, it first performs ToNumber on number objects (which each of
these are) to get the number value, which itself indirectly calls
`valueOf`. The first calls `Number.prototype.valueOf` with a number,
which makes sense. The second creates an object with a [[NumberData]]
internal slot, as expected, but it tries to call
`String.prototype.valueOf` because the prototype of the object is set
to `new.target.prototype === String.prototype` on creation. And by
spec, that throws if the object doesn't have a [[StringData]] slot
(which the `Number` constructor doesn't set, of course).

It's a similar situation with the third, but it's a little more
indirect. First it calls `Object.prototype.valueOf` because
`new.target.prototype === Object.prototype` when constructing the
number. But this returns an object, not a primitive. in the ToNumber
algorithm, if `valueOf` returns a non-primitive, it falls back to
`Object.prototype.toString()`, and in either case, recursively coerces
*that*. The result of coercing that result, `"[object Number]"`, to a
number is `NaN`, and `JSON.stringify(NaN)` returns `null` due to step
9.a/9.b in the SerializeJSONProperty algorithm (`NaN` is not a finite
number).

-

Isiah Meadows
cont...@isiahmeadows.com
www.isiahmeadows.com


On Sat, Aug 4, 2018 at 10:50 PM, Claude Pache  wrote:
>
>
> Le 5 août 2018 à 01:43, Michael Theriot  a
> écrit :
>
>> Try `Number.prototype.valueOf.call(obj)`: it will throw a TypeError if and
>> only if `obj` has no [[NumberData]] internal slot. Ditto for String, Boolean
>> and Symbol.
>
>
> I already mention this and demonstrate why it is not sufficient in my
> example.
>
> Reiterated plainly:
> ```js
> JSON.stringify(Reflect.construct(Number, [], Number)); // "0"
> JSON.stringify(Reflect.construct(Number, [], String)); // TypeError
> JSON.stringify(Reflect.construct(Number, [], Object)); // null
> ```
>
>
> Per spec, the three expressions should produce `"0"`, as the three objects
> have a [[NumberData]] internal slot (step 4 of [1]). I guess there is some
> discrepancy between implementation and spec for those exotic edge cases?
>
> [1]: https://tc39.github.io/ecma262/#sec-serializejsonproperty
>
> —Claude
>
>
>
> ___
> es-discuss mailing list
> es-discuss@mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Implementing an identical JSON.stringify

2018-08-04 Thread Claude Pache


> Le 5 août 2018 à 05:07, Claude Pache  a écrit :
> 
> 
> 
>> Le 5 août 2018 à 04:50, Claude Pache > > a écrit :
>> 
>> 
>> 
>>> Le 5 août 2018 à 01:43, Michael Theriot >> > a écrit :
>>> 
>>> Try `Number.prototype.valueOf.call(obj)`: it will throw a TypeError if and 
>>> only if `obj` has no [[NumberData]] internal slot. Ditto for String, 
>>> Boolean and Symbol.
>>> 
>>> I already mention this and demonstrate why it is not sufficient in my 
>>> example.
>>> 
>>> Reiterated plainly:
>>> ```js
>>> JSON.stringify(Reflect.construct(Number, [], Number)); // "0"
>>> JSON.stringify(Reflect.construct(Number, [], String)); // TypeError
>>> JSON.stringify(Reflect.construct(Number, [], Object)); // null
>>> ```
>> 
>> Per spec, the three expressions should produce `"0"`, as the three objects 
>> have a [[NumberData]] internal slot (step 4 of [1]). I guess there is some 
>> discrepancy between implementation and spec for those exotic edge cases?
>> 
>> [1]: https://tc39.github.io/ecma262/#sec-serializejsonproperty 
>> 
>> 
>> —Claude
>> 
> 
> I see that there is a difference in this algorithm between the current spec 
> and ES 2015 for that particular step. From my tests, current stable Firefox 
> and Safari (other browsers not tested) still follow the old algorithm.
> 
> —Claude
> 
> 
Nevrmind, forget the previous message. The algorithm does indeed somewhat 
strange here.

—Claude

___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Implementing an identical JSON.stringify

2018-08-04 Thread Claude Pache


> Le 5 août 2018 à 04:50, Claude Pache  a écrit :
> 
> 
> 
>> Le 5 août 2018 à 01:43, Michael Theriot > > a écrit :
>> 
>> Try `Number.prototype.valueOf.call(obj)`: it will throw a TypeError if and 
>> only if `obj` has no [[NumberData]] internal slot. Ditto for String, Boolean 
>> and Symbol.
>> 
>> I already mention this and demonstrate why it is not sufficient in my 
>> example.
>> 
>> Reiterated plainly:
>> ```js
>> JSON.stringify(Reflect.construct(Number, [], Number)); // "0"
>> JSON.stringify(Reflect.construct(Number, [], String)); // TypeError
>> JSON.stringify(Reflect.construct(Number, [], Object)); // null
>> ```
> 
> Per spec, the three expressions should produce `"0"`, as the three objects 
> have a [[NumberData]] internal slot (step 4 of [1]). I guess there is some 
> discrepancy between implementation and spec for those exotic edge cases?
> 
> [1]: https://tc39.github.io/ecma262/#sec-serializejsonproperty 
> 
> 
> —Claude
> 

I see that there is a difference in this algorithm between the current spec and 
ES 2015 for that particular step. From my tests, current stable Firefox and 
Safari (other browsers not tested) still follow the old algorithm.

—Claude


___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Implementing an identical JSON.stringify

2018-08-04 Thread Darien Valentine
> Per spec, the three expressions should produce "0", as the three objects
have a [[NumberData]] internal slot (step 4 of [1]). I guess there is some
discrepancy between implementation and spec for those exotic edge cases?

There’s no discrepancy — they shouldn’t all produce "0", because the
algorithm calls ToNumber on the value if it has the [[NumberData]] slot.
This in turn calls ToPrimitive because the value is an object. This
ultimately ends up calling the `@@toPrimitive` or `toValue` method _of_ the
object. In the case of the object with String.prototype for its prototype,
this will be `String.prototype.toValue`, which throws if its receiver
doesn’t have [[StringData]]. In the case of the object with
Object.prototype for its prototype, this will be `Object.prototype.toValue`.

On Sat, Aug 4, 2018 at 10:31 PM Darien Valentine 
wrote:

> Oh, thanks Claude, I missed that. I guess it is all replicable then.
>
> On Sat, Aug 4, 2018 at 10:28 PM Claude Pache 
> wrote:
>
>>
>>
>> > Le 5 août 2018 à 04:14, Darien Valentine  a
>> écrit :
>> >
>> >
>> > However it is ultimately not possible to replicate because there is no
>> possible brand test for [[BooleanData]].
>>
>> Per spec, checking whether `Boolean.prototype.valueOf.call(obj)` throws
>> will test whether an object has [[BooleanData]] internal slot.
>>
>> —Claude
>>
>>
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Implementing an identical JSON.stringify

2018-08-04 Thread Claude Pache


> Le 5 août 2018 à 01:43, Michael Theriot  a 
> écrit :
> 
> Try `Number.prototype.valueOf.call(obj)`: it will throw a TypeError if and 
> only if `obj` has no [[NumberData]] internal slot. Ditto for String, Boolean 
> and Symbol.
> 
> I already mention this and demonstrate why it is not sufficient in my example.
> 
> Reiterated plainly:
> ```js
> JSON.stringify(Reflect.construct(Number, [], Number)); // "0"
> JSON.stringify(Reflect.construct(Number, [], String)); // TypeError
> JSON.stringify(Reflect.construct(Number, [], Object)); // null
> ```

Per spec, the three expressions should produce `"0"`, as the three objects have 
a [[NumberData]] internal slot (step 4 of [1]). I guess there is some 
discrepancy between implementation and spec for those exotic edge cases?

[1]: https://tc39.github.io/ecma262/#sec-serializejsonproperty 


—Claude


___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Implementing an identical JSON.stringify

2018-08-04 Thread Darien Valentine
Oh, thanks Claude, I missed that. I guess it is all replicable then.

On Sat, Aug 4, 2018 at 10:28 PM Claude Pache  wrote:

>
>
> > Le 5 août 2018 à 04:14, Darien Valentine  a
> écrit :
> >
> >
> > However it is ultimately not possible to replicate because there is no
> possible brand test for [[BooleanData]].
>
> Per spec, checking whether `Boolean.prototype.valueOf.call(obj)` throws
> will test whether an object has [[BooleanData]] internal slot.
>
> —Claude
>
>
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Implementing an identical JSON.stringify

2018-08-04 Thread Claude Pache


> Le 5 août 2018 à 04:14, Darien Valentine  a écrit :
> 
> 
> However it is ultimately not possible to replicate because there is no 
> possible brand test for [[BooleanData]].

Per spec, checking whether `Boolean.prototype.valueOf.call(obj)` throws will 
test whether an object has [[BooleanData]] internal slot.

—Claude

___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Re: Implementing an identical JSON.stringify

2018-08-04 Thread Darien Valentine
Is this a question about how/if one could replicate its behavior in theory
from ES code, or are you suggesting a change to the existing behavior for
these exotic cases?

Assuming the former:

The relevant steps are [here](
https://tc39.github.io/ecma262/#sec-serializejsonproperty). The
`instanceof` a value isn’t significant in this algorithm, just its slots
(if it is an object) or its primitive type. So one can handle number and
string by leveraging branded checks as you’ve shown — nothing more is
needed than branded methods and typeof to manage that one.

However it is ultimately not possible to replicate because there is no
possible brand test for [[BooleanData]].
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Implementing an identical JSON.stringify

2018-08-04 Thread Michael Theriot
>
> Try `Number.prototype.valueOf.call(obj)`: it will throw a TypeError if and
> only if `obj` has no [[NumberData]] internal slot. Ditto for String,
> Boolean and Symbol.


I already mention this and demonstrate why it is not sufficient in my
example.

Reiterated plainly:
```js
JSON.stringify(Reflect.construct(Number, [], Number)); // "0"
JSON.stringify(Reflect.construct(Number, [], String)); // TypeError
JSON.stringify(Reflect.construct(Number, [], Object)); // null
```

Even though both of these have [[NumberData]] internal slots, it also
considers the type when throwing. Hence the question if you can type check
cross-realm in a way that does not depend on internal slots.

On Sat, Aug 4, 2018 at 6:35 PM Claude Pache  wrote:

>
>
> > Le 5 août 2018 à 00:16, Michael Theriot 
> a écrit :
> >
> > `JSON.stringify` has unintuitive behavior regarding interal slots.
>
> I don’t think that anything involving an object that has a [[StringData]]
> internal slot but has `Number.prototype` in its prototype chain could have
> an ”intuitive” behaviour...
>
> >
> >
> > I think this is related to `Array.isArray`. Is there an equivalent
> `Number.isNumber`? Or is this just something only `JSON.stringify` can do?
>
> Try `Number.prototype.valueOf.call(obj)`: it will throw a TypeError if and
> only if `obj` has no [[NumberData]] internal slot. Ditto for String,
> Boolean and Symbol.
>
> —Claude
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Implementing an identical JSON.stringify

2018-08-04 Thread Claude Pache


> Le 5 août 2018 à 00:16, Michael Theriot  a 
> écrit :
> 
> `JSON.stringify` has unintuitive behavior regarding interal slots.

I don’t think that anything involving an object that has a [[StringData]] 
internal slot but has `Number.prototype` in its prototype chain could have an 
”intuitive” behaviour...

> 
> 
> I think this is related to `Array.isArray`. Is there an equivalent 
> `Number.isNumber`? Or is this just something only `JSON.stringify` can do?

Try `Number.prototype.valueOf.call(obj)`: it will throw a TypeError if and only 
if `obj` has no [[NumberData]] internal slot. Ditto for String, Boolean and 
Symbol.

—Claude
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss