Allen Wirfs-Brock (2013-07-30T01:09:29.000Z)
domenic at domenicdenicola.com (2013-08-04T22:35:07.282Z)
On Jul 29, 2013, at 5:11 PM, David Bruant wrote: > 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) Nope. We would have had the same problems if we had kept [[Class]]. In ES<=5.1 [[Class]] is used to conflate situational specific testing for a number of independent characteristics of objects. Some of those characteristics can not be transparently prloxied (for example this object reference directly refers a special object representation with some specific implementation dependent representation of some private state 0) > 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. > 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. One of the goals for ES6 proxies was to enable self-hosting of built-ins. In theory, there is no reason that a proxy couldn't be use buy an implementation to implement its "exotic array objects". However, because the spec. explicitly distinguishes "exotic array objects" from other built-in exotic object and from general proxies, such a host implementation would still have to have a way to identify the proxy-implemented exotic arrays as such and for test for them in every context where the spec. says an "exotic array object" is required. That branding test would be that implementations way of implementing "is O is an exotic Array 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. > In any case, regardless of how many tests a proxy passes, it has always a way to wrongly behave after having passed the test. The key things are hard dependencies between native code built-in methods that expect specific fixed object layouts and the actual instances of those objects. > Excellent. > It also means that any proxy that customizes its @@toStringTag could have O.p.toString return "[object Array]", right? right, but I forgot about step 20.e of Object.prototype.toString in the current draft. This tries to prevent using @@toStringTag to return any of the ES<6 era [[Class]] tags. There is past controversy about that step. Some think such aliased results should be allows (eg, the use case I described just above). Other think that it should throw in this case rather than the current hack in the spec. There is also an argument that permitting something other than a true exotic array (for example) to return "[object Array]]" could be a breaking change if such an object is encountered by some legacy code. > Saving existing code from proxies is a dead end in my opinion. This has nothing to do with Proxies. Consider: ```js var x = [__proto__: Array.prototype]. ``` In ES<=5.1 ```js Object.prototype.toString(x) //returns "[object Object]" ``` If in ES6, Array.prototype has an built-in @@toStringTag property whose value is "Array" then: ```js Object.prototype.toString(x) //returns "[object Array]" ``` > I don't really understand what you're testing here to checking the length invariant. It's an implementation internal test. It is what it means to be "an exotic array object". See 8.4.2 of the current ES6 draft for the complete specification of what it means to be an "exotic array object" > Can a proxy be written to pass this test? no, not with portable ES code. The logic is within Array.isArray, not within the object it is applied to. > Can a proxy be written so that the value of this test changes over time? no > Maybe a test on whether the value is iterable? (so that replacer can also be a Set, etc.) That would be an extension to the current JSON.stringify functionality. Not implausible, but nobody has proposed any such changes for ES6. > 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. What do you mean to "be a Date". The ES6 spec. defines Dateness very specifically. It is an ordinary object (ie, not a Proxy) that has a [[DateValue]] internal data property that can be recognized as such by an implementation. The only way the ES6 spec. provides for creating such an object is via the Date[[@@create]] method defined in 15.9.3.5 of the current draft. This method is inherited by subclass constructors so instances of subclasses of the Date constructor, by default, also will pass the Dateness test. However, the this is not a very interesting test. It is only used to make sure that built-in Date.prototype methods that assume that they have direct access to a [[DateValue]] slot actually are operating upon such an object. Application level JS code really should not be doing such pseudo-nominal type testing. At the application level, JS operates best using dynamic behavioral types. If an object has the methods specified for Date instances and those methods return the expected results, why do you case whether or not you are dealing with an instance of the original built-in Date or an instance of somebodies alternative Date implementation. Similarly, the ES6 spec. is careful to make sure that an object that is an instance of an enhanced or alternative regular expression engine can be used anyplace a built-in RegExp object was previously required.