David Bruant (2013-07-30T00:11:14.000Z)
Le 29/07/2013 20:41, Allen Wirfs-Brock a écrit :
> The legacy [[Class]] internal property conflated these two concepts.  Sometimes it was used for to ensure that a built-in method was operating upon an instance that actually had the internal state or conformed to other implementation level invariants needed by the method. Other times, [[Class]] was tested  for basic external behavioral classification purposes that don't really care at all about implementation level object invariants.
>
> In most cases, the ES6 spec. language such as  "if O is an exotic X object" or "does X have a [[XXX]] internal data property" works fine as a direct replacement of an ES5  [[Class]] test because there are a one-to-one correspond between a ES6 built-in that is represented by specific kind of exotic object or that has a specific internal data property and with a ES5 built-in with the corresponding [[Class]] value.
Can all the [[Class]] replacement tests be passed by proxies in a way or 
another so that a proxy can impersonate a given "class" of exotic 
object? (most likely by having one of these objects as target)

Also, I fail to understand the difference between "if O is an exotic X 
object" and "if O.[[Class]] === X".

>> If proxies for arrays do not pass such tests, some built-ins behave in unexpected ways.
> What's expected?  Just because a proxy has an exotic array object as its target doesn't mean that is functions as an exotic array.
This suggests that the opposite could be true, that is that a proxy with 
any target might impersonates an array as long as it passes some tests. 
I wonder how much of a good idea this is.

The (granted implicit) model of "a proxy for exotic object X is seen by 
all algorithms as an exotic object X" feels simpler even if it means 
that a proxy might not act as an internal algorithm expects.
In any case, regardless of how many tests a proxy passes, it has always 
a way  to wrongly behave after having passed the test.

>> Here's the list of relevant built-ins, based on searching the ES6 spec for "is an exotic Array object":
>> * Object.prototype.toString
> As currently spec'ed. toString will invoke the HasProperty(@@toStringTag) of the proxy and if the result is true invoke the Get trap to retrieve the value used to construct the toString result. All of the new built-ins have @@toStringTag methods.  I considered adding them for the built--ins that carry over from ES5.  Then, if the @@toStringTag of Array.prototype is "Array" then Object.prototype.toString(new Proxy([ ], { })) should return "[Object Array]".
Excellent.
It also means that any proxy that customizes its @@toStringTag could 
have O.p.toString return "[Object Array]", right?

> However, this would be a breaking change for existing code explicitly wires their prototype chain to inherit from Array.prototype.
Saving existing code from proxies is a dead end in my opinion.

>> * Array.isArray
> We've discussed the meaning of this in the past and have agreed that it should be considered a test for exotic array-ness and in particular the length invariant. A Proxy whose target is an exotic array may or may not qualify.
I don't really understand what you're testing here to checking the 
length invariant.
Can a proxy be written to pass this test?
Can a proxy be written so that the value of this test changes over time?

>> * JSON.stringify
> There are two distinct use cases of [[Class]]==Array in the ES5 spec of this function.  Both are currently in the ES6 spec. as  exotic array tests.  The first use case is to see if the "replaceer" argument is an white-list array.  This could be special cased via a @@isJSONArray that would work through a proxy, but  I dubious that the additional complexity is justified.
Maybe a test on whether the value is iterable? (so that replacer can 
also be a Set, etc.)

>> It's worth noting that I hit upon these issues because users of my harmony-reflect shim, which are using direct proxies today in ES5, have reported them (see [1],[2]). This adds some evidence that users expect the above built-ins to behave transparently w.r.t. proxies for their use cases. My library patches some of these built-ins to recognize my own emulated proxies, but this is just an ad hoc solution. ES6 users will obviously not be able to do this.
> They may expect this, but I don't see what generalizations we can make.  Whether a proxy over a built-in is behaviorally substitutable for the built-in completely dependent upon the the definition of the specific proxy.
Again, this seems to suggest that a proxy could pretend to be a Date to 
one algorithm, an Array to another and a RegExp to another. I'm not sure 
what good comes out of that.

David
domenic at domenicdenicola.com (2013-08-04T22:32:21.466Z)
Le 29/07/2013 20:41, Allen Wirfs-Brock a écrit :
> The legacy [[Class]] internal property conflated these two concepts.  Sometimes it was used for to ensure that a built-in method was operating upon an instance that actually had the internal state or conformed to other implementation level invariants needed by the method. Other times, [[Class]] was tested  for basic external behavioral classification purposes that don't really care at all about implementation level object invariants.
>
> In most cases, the ES6 spec. language such as  "if O is an exotic X object" or "does X have a [[XXX]] internal data property" works fine as a direct replacement of an ES5  [[Class]] test because there are a one-to-one correspond between a ES6 built-in that is represented by specific kind of exotic object or that has a specific internal data property and with a ES5 built-in with the corresponding [[Class]] value.

Can all the [[Class]] replacement tests be passed by proxies in a way or 
another so that a proxy can impersonate a given "class" of exotic 
object? (most likely by having one of these objects as target)

Also, I fail to understand the difference between "if O is an exotic X 
object" and "if O.[[Class]] === X".

>> If proxies for arrays do not pass such tests, some built-ins behave in unexpected ways.
>
> What's expected?  Just because a proxy has an exotic array object as its target doesn't mean that is functions as an exotic array.

This suggests that the opposite could be true, that is that a proxy with 
any target might impersonates an array as long as it passes some tests. 
I wonder how much of a good idea this is.

The (granted implicit) model of "a proxy for exotic object X is seen by 
all algorithms as an exotic object X" feels simpler even if it means 
that a proxy might not act as an internal algorithm expects.
In any case, regardless of how many tests a proxy passes, it has always 
a way  to wrongly behave after having passed the test.

>> Here's the list of relevant built-ins, based on searching the ES6 spec for "is an exotic Array object":
>> * Object.prototype.toString
>
> As currently spec'ed. toString will invoke the HasProperty(@@toStringTag) of the proxy and if the result is true invoke the Get trap to retrieve the value used to construct the toString result. All of the new built-ins have @@toStringTag methods.  I considered adding them for the built--ins that carry over from ES5.  Then, if the @@toStringTag of Array.prototype is "Array" then Object.prototype.toString(new Proxy([ ], { })) should return "[Object Array]".

Excellent.
It also means that any proxy that customizes its @@toStringTag could 
have O.p.toString return "[Object Array]", right?

> However, this would be a breaking change for existing code explicitly wires their prototype chain to inherit from Array.prototype.

Saving existing code from proxies is a dead end in my opinion.

>> * Array.isArray
>
> We've discussed the meaning of this in the past and have agreed that it should be considered a test for exotic array-ness and in particular the length invariant. A Proxy whose target is an exotic array may or may not qualify.

I don't really understand what you're testing here to checking the 
length invariant.
Can a proxy be written to pass this test?
Can a proxy be written so that the value of this test changes over time?

>> * JSON.stringify
>
> There are two distinct use cases of [[Class]]==Array in the ES5 spec of this function.  Both are currently in the ES6 spec. as  exotic array tests.  The first use case is to see if the "replaceer" argument is an white-list array.  This could be special cased via a @@isJSONArray that would work through a proxy, but  I dubious that the additional complexity is justified.

Maybe a test on whether the value is iterable? (so that replacer can 
also be a Set, etc.)

>> It's worth noting that I hit upon these issues because users of my harmony-reflect shim, which are using direct proxies today in ES5, have reported them (see [1],[2]). This adds some evidence that users expect the above built-ins to behave transparently w.r.t. proxies for their use cases. My library patches some of these built-ins to recognize my own emulated proxies, but this is just an ad hoc solution. ES6 users will obviously not be able to do this.
>
> They may expect this, but I don't see what generalizations we can make.  Whether a proxy over a built-in is behaviorally substitutable for the built-in completely dependent upon the the definition of the specific proxy.

Again, this seems to suggest that a proxy could pretend to be a Date to 
one algorithm, an Array to another and a RegExp to another. I'm not sure 
what good comes out of that.