On Nov 12, 2014, at 12:12 PM, Tom Van Cutsem <[email protected]> wrote:

> 2014-11-12 19:53 GMT+01:00 Rick Waldron <[email protected]>:
> I agree and I want to know if you think this is worth revisiting once more? 
> Next meeting's agenda?
> 
> I don't think we've ever discussed this issue before during a TC39 meeting 
> (but I didn't attend quite a few, so I may be wrong). Adding it to the agenda 
> for next meeting seems good to me.
> 

Yes, this has been discussed at TC39 meetings although I’d have to go search 
notes for a record of it.  Regardless, I’ll try to summarize the logic that 
lead to the current decision.

First Array.isArray was introduced in ES5 to provide a reliable way to detect 
Array instances that works regardless of what realm created the instance. In 
ES5, Array.isArray  is specified as a test whether the [[Class]] internal 
property has the the value “Array”.  In ES5 the only objects that have that 
[[Class]] values are objects created use the Array constructor or using an 
Array literal (or internally instantiated objects created “as if” by `new 
Array`).  Any such object responds true for Array.isArray even if its 
[[Prototype]] is set (using __proto__) to something different than 
Array.prototype. 

All ES5 objects for which Array.isArray answers true have exotic `length` 
behavior where adding an index property beyond the current `length` increases 
the value of `length` and deleting training index properties decrease the value 
of `length`.

ES6 eliminates the [[Class]] internal properties, but the equivalent is any 
object that is an “exotic array object’ .  Any “exotic array object” is an 
exotic object whose [[DefineProperty]] internal method maintains the `length` 
property invariant described above.  ES6 specifies that Array.isArray answers 
true only for exotic array objects. Given any ES5-level ES code, the ES6 spec. 
will produce exactly the same result of Array.isArray as was produced by ES5.

In deciding the ES6 behavior for Array.isArray we considered at least four 
significant issues:
1) Backwards compatibility with ES5 level code that uses ES5.1.  It must 
produce the same result for all such code. This includes code that does 
__proto__ hacking.

2) ES6 subclassing.  Given `let sa = new (class extends Array {});`  what 
should be the value of `Array.isArray(sa)` ?  This is something we explicitly 
talked about at TC39 meetings and agreed that the answer should be true (except 
when…).  However, there are really two kinds of subclass to consider. 
Subclasses of Array that automatically inherit the creation of exotic array 
object instances and subclasses of Array that explicit over-ride in their 
constructor to produce some other kind of instance object (an ordinary object 
or perhaps some other kind of exotic object or a Proxy).  Note this is roughly 
equivalent to ad hoc ES5 subclassing where you might either use __proto__ to 
change the [[Prototype]] of an array instance to something other than 
Array.prototype or where you might create an ordinary object (not an Array 
instance) and set its [[Prototype]] to Array.prototype in order to inherit 
Arrray.prototype methods. In the TC39 discussions we concluded that the exotic 
array based isArray definition gives reasonable answers for both ES5 and Es6 
subclassing.

3) Proxies. Should Array.isArray treat proxy instances specially? To answer 
this question we need to think about what a ES programmer actually thinks 
Array.isArray means? The meaning that ES5 established is that Array.isArray 
returning true means that the object observably maintains the array `length` 
invariant. There is no general way to determine whether this invariant is true 
for an arbitrary proxy.  Checking if the proxy’s target object is an exotic 
array object isn’t sufficient to say isArray is true because the 
defineProperty/get/set/delete traps might not maintain the invariant.  Similar, 
checking that the object is an ordinary object isn’t suffiient for isArray to 
say false because appropriate the handler may impose the array `length` 
invariants upon an ordinary object.

4)Self-hosting Array. An ES6 goal was to allow self-hosting of built-ins using 
Proxy where necessary to implement self-hosted exotic objects. A implementation 
could self-host Array by using a Proxy that targeted an ordinary object and a 
handler that maintained the `length` invariants. However, if it did this, it 
would also have to provide an implementation of Array.isArray that was able to 
recognize those Proxy based self-hosted Array instances.  It might by using 
some sort of private tagging mechanism of Array instances (for example via a 
WeakSet) that it’s Array.isArray would recognize.

The current ES6 definition still seems like the best definition, if you accept 
that Array.isArray means "does this object maintain the `length` invariant?" 
Tunneling through a Proxy and testing if its target is an exotic array object 
isn’t an adequate fix, because of the reasons mentioned above.

In the end, this is really about what JS programmers think Array.isArray means 
and why they would want to call it.  One of the main motivating use cases 
during ES5 development was the JSON behavior of stringifying Array instances 
differently from non-Array instances. In retrospect, Array.isArray is 
improbably not the best way to address that use case.  If we were doing it over 
in ES6 I probably would have defined an @@stringifyAsArray property on 
Array.prototype and made JSON.stringify sensitive to the presence of that 
property. 

What are other reasonable use cases for Array,isArray?

Allen









> regards,
> Tom
> _______________________________________________
> es-discuss mailing list
> [email protected]
> https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to