Allen Wirfs-Brock (2013-07-30T16:57:04.000Z)
On Jul 30, 2013, at 1:25 AM, David Bruant wrote:

> 
> 2013/7/30 Allen Wirfs-Brock <allen at wirfs-brock.com>
> 
> On Jul 29, 2013, at 7:04 PM, David Bruant wrote:
> 
>> Le 30/07/2013 03:09, Allen Wirfs-Brock a écrit :
>>> On Jul 29, 2013, at 5:11 PM, David Bruant wrote:
> ...
> no special "this" here.  I'm just saying that at the implementation level, when you are doing  something with an object value what you really have is a "reference" (ie a pointer) to a heap allocated data structure.  If the implementation code is going to do something that depends on the data structures actual memory layout, then you better be sure that you have a pointer to the actual data structure you expect. 
> This apply to Date and the "time value", but I fail to see why this doesn't apply to every object and every property. For instance, every object is expected to have a [[Prototype]] object (at least in the ES5 era), which most likelty had a reserved slot in current implementations. Proxies challenge this, because they don't have a [[Prototype]], so the same sort of "memory safety hazard" apply for [[Prototype]].
> But I'm not too worry about that. I imagine implementors are well-aware of how deeply proxies are to integrate (retrofit!) in the object model. They'll figure it out for Date objects as well.
> 

It's important to be clear here that things Date's "time value" slot, the [[DateValue]] internal data property, are not actual "Properties".  They represent private internal per instance state that is not accessible through any of the normal property access mechanisms. It is an unfortunate accident of history that we use  the word "property" in talking about them. I've considered using replacing "internal data property" with another term.  Maybe I should just go ahead and change over to calling "private data slots".

So far in ES<=6 dealing with such private data slots is something that could be treated in a relatively ad hoc manner within the ES spec. and by implementations.  But in ES7 we really want and need user definable per instance private data. The issues we are encountering here are a precursor of the issue we will see down the line and what we do now may constrain what we can do later. 

[[Prototype]] and other aspects of the basic ES object model are specified as part of  the MOP (section 8.1.6.2) and mirrored by the Proxy handler interface.  Every object whether ordinary, exotic, built-in, host-provided, etc. must expose the MOP interface to the implementation.  Supporting that interface is what it means to be an ES object. "private data slots" are not part of the MOP, they represent an implementation specific side-channel.

Strictly speaking, the MOP accesses the inheritance prototype chain via the [[GetInheritance]]/[[SetInheritance]] MOP operation.  [[Prototype]] is just an internal data slot that ordinary objects use as backing store for those operations.  Exotic objects do not necessary have a [[Prototype]] internal data slot.  Proxy exotic objects and the currently spec. for Symbol exotic objects are examples of objects that don't need a [[Prototype]] internal data property.

...
>  
> 
> For a broader discussion of the use of [[Class]] in ES5 see https://docs.google.com/document/d/1sSUtri6joyOOh23nVDfMbs1wDS7iDMDUFVVeHeRdSIw/edit?hl=en&authkey=CI-FopgC&pli=1 
> Cases are annoyingly numerous, but finite. A test suite can go a long way. I heard the test suite is moving to Github :-) Only missing is an extensive doc of the test framework.

Tests are normative and you can't write a valid test suite in the absence of an accurate specification. 


>  
>>>> Also, I fail to understand the difference between "if O is an exotic X object" and "if O.[[Class]] === X".
>>> There really isn't much.  But getting rid of [[Class]] enables us to separate the previously conflated characteristics.
>> When you test for "if O is an exotic array object", what characteristic are you testing for, then?
>> This still feels like branding to me.
> 
> It is exactly branding, but branding for the specific characteristics that are defined ES6 clause 8.4.2.  It doesn't include other things that [[Class]] was sometimes used for.
> If the intent behind branding is "internal memory layout", I argue that this is implementation details leaking into abstraction and that it's a bad idea especially as it serves no purpose other than memory safety issues that *might* happen in the transition era between the "before proxy" world and the "after proxy" world.
>  
> 
>> So self-hosted code can distinguish an actual array from a proxy, that's not an issue.
>> Non-privileged code being able to distinguish an array and a proxy for an array is more worrisome.
> 
> I go the other way, in general there should be nothing special about  "self-hosting code".  Perhaps the phrase is even misleading. What I'm really saying that there should be no particular reason that anything other than the most primitive elements of the the ES built-ins can't be expressed in ES code.
> 
> A proxy with an Array as its target is not an Array.  Whether such an object is substitutable for an Array instance is high dependent on the details of its handler and other aspects of its implementation.   Also please see http://wiki.ecmascript.org/doku.php?id=harmony:virtual_object_api which address related issues.
> This is not enough.
> this-binding ("proxy.getMonth()" when the target is a Date) is only half of the story. The other half remains unadressed ("Date.prototype.getMonth.call(proxy)"). Exotic objects aren't always used as "this" value. This is exactly Tom's feedback actually.
> We need the same solution for both cases (this and non-this usage of methods).

I also raised this objection and it is what led to the recent update to the virtual object API referenced above.  What that change does is make it easier for ES programmer to create proxies that behave in this manner.

But, in the end we could not come up with a solution for the Date.prototype.getMonth.call(proxy) issue.  The [[Invoke]] MOP operation/trap was added to minimize the actual occurrence of this scenario.  You can't use 'call' to force a built-in to operate upon the wrong kind of object. 

>  
> 
>>>> 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.
>>> memory safety hazard.  Every place that checks for "is O an exotic X object" would have to have a subsequent "is O a Proxy whose target is an exotic X" and take different code paths.  If you screw it up, you may have memory safety issues.
>> That's an implementation hazard; not sure what your point is here.
> 
> The major of such test in the spec. are abstracting over such implementation hazards.  That's why they are there.
> Let's let implementors deal with implementation issues. Let's just make sure the spec isn't impossible or too high barrier to implement. A test suite will do the rest. Let's care only for tests that make sense when authoring.
> Implementors are free to dive in here to say I'm wrong and why.

ES spec. largely exists to constrain how implementors deal with such issue in order to guarantee that different implementations have observably identical behavior. 

I think you are glossing over real issues that require real design thinking and which probably can't be addressed until ES7. With no offense to TomVC (who does the best job of any of our contributors in producing sound spec. material), I think the original Proxy strawman treatment of [[Class]]  was gloss.

I complete disagree WRT tests. Tests written without reference to some normative specification are just a reflection of how their developer thinks the system should work.


> ...
>  
>> Something has to be given up. And giving up on indistinguishability would defeat the purpose of proxies (and the expectation as feedback on Tom's library suggests).
> 
> You suggestion is?  My point is ES internal branding, whether you call it "check for exotic XXX object", "check for the[[XXX]] internal data property" or check if [[Class]] == "Array" h does not work with the Direct Proxy default handler semantics.
> Is there a handler semantics with which it can fully work? That's all is needed.

The ForwardingHandler semantics is close to what you want.  But it still doesn't work the way you would like for direct "call" invocation or for things like Array.isArray.  The base issue for either of these is that they don't indirect through the proxy handler and hence the handler doesn't have an opportunity to replace the proxy reference with the target reference.  
> ... 
> 
>  
> Is this a Date according to what you have in mind:
> 
> let obj = new Date();
> obj.__proto__ = null;
> The definition used in most spec algorithms is "has a this time value", so I guess this passes.

Yes, it is sufficient for the spec algorithms which is a safety check that  is only making sure that you don't apply a Date method to an object that doesn't have the required implementation level time value slot.

But you are talking about the application layer .  It is easy to say you want a way to "test if an object is a Date" or "is an Array".  But what do you mean by those concepts at the application level.  The ES spec. internally is able to make such tests, conforming to the internal invariants it needs to maintain.  But those invariants aren't necessarily what you are asking for at the application level. 

At the root of this thread is the question of what does Array.isArray actually test and what are its application level use cases..  Array.isArray was a new method that was added in ES5.  It wasn't added as a test to see if an object conformed to some Platonic Ideal of array-ness. It was specifically a reliable iframe-independent  test for instances of the Array built-in constructor. I'm not really sure whether that is actually a very important use case, but that was the specific use case it was designed for.  

Do you have new use cases, that motivate the design of an enhanced Array.isArray?

It would be quite easy to extend Array.isArray(obj) so that it delegated back to obj with a @@areYouAnArray method such as we are doing with @@isRegExp in certain places.  However, if we do that you loose support for the original Array.isArray use case because any object could decide to return true from Array.isArray. 
...

> This thread feedback brings new data and it seems that the current handler offering isn't enough (and I understand can't be).

yup

Allen
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20130730/1908edb6/attachment-0001.html>
domenic at domenicdenicola.com (2013-08-04T22:53:03.957Z)
On Jul 30, 2013, at 1:25 AM, David Bruant wrote:

> This apply to Date and the "time value", but I fail to see why this doesn't apply to every object and every property. For instance, every object is expected to have a [[Prototype]] object (at least in the ES5 era), which most likelty had a reserved slot in current implementations. Proxies challenge this, because they don't have a [[Prototype]], so the same sort of "memory safety hazard" apply for [[Prototype]].
> But I'm not too worry about that. I imagine implementors are well-aware of how deeply proxies are to integrate (retrofit!) in the object model. They'll figure it out for Date objects as well.

It's important to be clear here that things Date's "time value" slot, the [[DateValue]] internal data property, are not actual "Properties".  They represent private internal per instance state that is not accessible through any of the normal property access mechanisms. It is an unfortunate accident of history that we use  the word "property" in talking about them. I've considered using replacing "internal data property" with another term.  Maybe I should just go ahead and change over to calling "private data slots".

So far in ES<=6 dealing with such private data slots is something that could be treated in a relatively ad hoc manner within the ES spec. and by implementations.  But in ES7 we really want and need user definable per instance private data. The issues we are encountering here are a precursor of the issue we will see down the line and what we do now may constrain what we can do later. 

[[Prototype]] and other aspects of the basic ES object model are specified as part of  the MOP (section 8.1.6.2) and mirrored by the Proxy handler interface.  Every object whether ordinary, exotic, built-in, host-provided, etc. must expose the MOP interface to the implementation.  Supporting that interface is what it means to be an ES object. "private data slots" are not part of the MOP, they represent an implementation specific side-channel.

Strictly speaking, the MOP accesses the inheritance prototype chain via the [[GetInheritance]]/[[SetInheritance]] MOP operation.  [[Prototype]] is just an internal data slot that ordinary objects use as backing store for those operations.  Exotic objects do not necessary have a [[Prototype]] internal data slot.  Proxy exotic objects and the currently spec. for Symbol exotic objects are examples of objects that don't need a [[Prototype]] internal data property.

> Cases are annoyingly numerous, but finite. A test suite can go a long way. I heard the test suite is moving to Github :-) Only missing is an extensive doc of the test framework.

Tests are normative and you can't write a valid test suite in the absence of an accurate specification. 

> This is not enough.
> this-binding ("proxy.getMonth()" when the target is a Date) is only half of the story. The other half remains unadressed ("Date.prototype.getMonth.call(proxy)"). Exotic objects aren't always used as "this" value. This is exactly Tom's feedback actually.
> We need the same solution for both cases (this and non-this usage of methods).

I also raised this objection and it is what led to the recent update to the virtual object API referenced above.  What that change does is make it easier for ES programmer to create proxies that behave in this manner.

But, in the end we could not come up with a solution for the Date.prototype.getMonth.call(proxy) issue.  The [[Invoke]] MOP operation/trap was added to minimize the actual occurrence of this scenario.  You can't use 'call' to force a built-in to operate upon the wrong kind of object. 

> Let's let implementors deal with implementation issues. Let's just make sure the spec isn't impossible or too high barrier to implement. A test suite will do the rest. Let's care only for tests that make sense when authoring.
> Implementors are free to dive in here to say I'm wrong and why.

ES spec. largely exists to constrain how implementors deal with such issue in order to guarantee that different implementations have observably identical behavior. 

I think you are glossing over real issues that require real design thinking and which probably can't be addressed until ES7. With no offense to TomVC (who does the best job of any of our contributors in producing sound spec. material), I think the original Proxy strawman treatment of [[Class]]  was gloss.

I complete disagree WRT tests. Tests written without reference to some normative specification are just a reflection of how their developer thinks the system should work.

> Is there a handler semantics with which it can fully work? That's all is needed.

The ForwardingHandler semantics is close to what you want.  But it still doesn't work the way you would like for direct "call" invocation or for things like Array.isArray.  The base issue for either of these is that they don't indirect through the proxy handler and hence the handler doesn't have an opportunity to replace the proxy reference with the target reference.  

> The definition used in most spec algorithms is "has a this time value", so I guess this passes.

Yes, it is sufficient for the spec algorithms which is a safety check that  is only making sure that you don't apply a Date method to an object that doesn't have the required implementation level time value slot.

But you are talking about the application layer .  It is easy to say you want a way to "test if an object is a Date" or "is an Array".  But what do you mean by those concepts at the application level.  The ES spec. internally is able to make such tests, conforming to the internal invariants it needs to maintain.  But those invariants aren't necessarily what you are asking for at the application level. 

At the root of this thread is the question of what does Array.isArray actually test and what are its application level use cases..  Array.isArray was a new method that was added in ES5.  It wasn't added as a test to see if an object conformed to some Platonic Ideal of array-ness. It was specifically a reliable iframe-independent  test for instances of the Array built-in constructor. I'm not really sure whether that is actually a very important use case, but that was the specific use case it was designed for.  

Do you have new use cases, that motivate the design of an enhanced Array.isArray?

It would be quite easy to extend Array.isArray(obj) so that it delegated back to obj with a @@areYouAnArray method such as we are doing with @@isRegExp in certain places.  However, if we do that you loose support for the original Array.isArray use case because any object could decide to return true from Array.isArray. 

> This thread feedback brings new data and it seems that the current handler offering isn't enough (and I understand can't be).

yup