Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-17 Thread Allen Wirfs-Brock

On Nov 16, 2014, at 11:08 PM, Tom Van Cutsem wrote:

 2014-11-17 3:34 GMT+01:00 Frankie Bagnardi f.bagna...@gmail.com:
 Consider when Array.isArray would be used.  In my experience, checks to see 
 if something is an array are used for:
 
  - deciding how to iterate it (for(;;) vs for..in, for example)
 
 This is a good one. Here, again, a typical proxy-for-array would work as 
 intended, as the for(;;) loop just queries .length and properties named 0, 
 1, ... via standard [[Get]] access.
 
 Can someone come up with a convincing example where a proxy-for-array would 
 *not* work as intended?
 (convincing here means it doesn't involve a proxy that blatantly violates 
 the Array contract on purpose)

Probably not, because the Array.prototype methods are all carefully coded to 
not have any internal slot or this identify dependencies.

But probing through the proxy as has been proposed is a terrible violation of 
the MOP API boundary and isn't generalizable to other built-ins that are 
dependent upon internal state. While a null handler proxy on a direct instance 
of Array would work under that design, a comparable Map.isMap or 
Promise.isPromise method would not.  Rather than a one-off hack I think we 
should use a new pattern that is generalizable:


Here is a proposal:

Array.isArray is redefined equivalently to:

```js
Array.isArray = function (obj) {
   let constructor = obj.constructor;
   If (typeof constructor != 'function') return false;
   return !!constructor[Symbol.isArray];
}
```

and also

```js
Array[Symbol.isArray]] = true;  //note, this is a constructor property, not an 
Array.prototype property.
```

we also change Array.prototype.concat to do the above Array.isArray test 
instead of using @@comcatSpreadable and change JSON.stringify to use this test 
where it current checks for an exotic array object.

Then we have the following:

assert(Array.isArray( [ ] ));  //just like ES5
assert( ! Array.isArray( Object.create(Array.prototype))); //just like ES5
assert (new class extends Array{});  //ES6 Array subclass instances answer true 
unless the subclass over-rides the static  @@isArray property
assert(new class extends Array {
   constructor() {return {}};
});   // even if the subclass instance isn't an exotic array object (this is an 
improvement over the current ES6 spec. which says that 
   //isArray answers false in this case
assert(new Proxy( [ ], { });  //because it's all done with property access, no 
instance inspection required.

assert( ! new Int32Array(10));  //not array-like, just like ES5

However, I think we should experiment with giving %TypedArrau% is true valued 
@@isArray property.  I'm guessing that this change won't actually break 
anything.

the above proposal completely decouples Array.isArray from exotic array object 
checking or any other direct instance inspection. Everything works at the 
property access level and so is (by default) transparent to proxies and 
completely controllable at the ES cod level. 

allen

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


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-17 Thread Brendan Eich

Allen Wirfs-Brock wrote:

```js
Array[Symbol.isArray]] = true;  //note, this is a constructor 
property, not an Array.prototype property.


Minomer, then -- how about Symbol.isArrayClass?

we also change Array.prototype.concat to do the above Array.isArray 
test instead of using @@comcatSpreadable and change JSON.stringify to 
use this test where it current checks for an exotic array object.


Then we have the following:

assert(Array.isArray( [ ] ));  //just like ES5
assert( ! Array.isArray( Object.create(Array.prototype))); //just like ES5


How so? True:

js Array.isArray(Array.prototype)
true
js Array.isArray(Object.create(Array.prototype))
false

but constructor isn't shadowed:

js Array.prototype.constructor
function Array() {
[native code]
}
js Object.create(Array.prototype).constructor
function Array() {
[native code]
}

assert (new class extends Array{});  //ES6 Array subclass instances 
answer true unless the subclass over-rides the static  @@isArray property

assert(new class extends Array {
   constructor() {return {}};
});   // even if the subclass instance isn't an exotic array object 
(this is an improvement over the current ES6 spec. which says that

   //isArray answers false in this case
assert(new Proxy( [ ], { });  //because it's all done with property 
access, no instance inspection required.


(These want Array.isArray inside assert, of course.)


assert( ! new Int32Array(10));  //not array-like, just like ES5

However, I think we should experiment with giving %TypedArrau% is true 
valued @@isArray property.  I'm guessing that this change won't 
actually break anything.


Probably ok.

the above proposal completely decouples Array.isArray from exotic 
array object checking or any other direct instance inspection. 
Everything works at the property access level and so is (by default) 
transparent to proxies and completely controllable at the ES cod level.


Righteous goal!

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


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-17 Thread Allen Wirfs-Brock

On Nov 17, 2014, at 11:06 AM, Brendan Eich wrote:

 Allen Wirfs-Brock wrote:
 ```js
 Array[Symbol.isArray]] = true;  //note, this is a constructor property, not 
 an Array.prototype property.
 
 Minomer, then -- how about Symbol.isArrayClass?

perhaps, I have a negative reaction to including the work class but can 
probably live with it.

 
 we also change Array.prototype.concat to do the above Array.isArray test 
 instead of using @@comcatSpreadable and change JSON.stringify to use this 
 test where it current checks for an exotic array object.
 
 Then we have the following:
 
 assert(Array.isArray( [ ] ));  //just like ES5
 assert( ! Array.isArray( Object.create(Array.prototype))); //just like ES5
 
 How so? True:
 
 js Array.isArray(Array.prototype)
 true
 js Array.isArray(Object.create(Array.prototype))
 false
 
 but constructor isn't shadowed:
 
 js Array.prototype.constructor
 function Array() {
[native code]
 }
 js Object.create(Array.prototype).constructor
 function Array() {
[native code]
 }

Shit, you're right.  This is the hard case for legacy compat using this 
technique. 

I think I see a way to make this give the legacy answer, but I suspect I can't 
make it give the same answer for
  Array.isArray(new Proxy(Object.create(Array.prototype), { }));
May limiting the WTF=ness to that case isn't so bad.

 
 assert (new class extends Array{});  //ES6 Array subclass instances answer 
 true unless the subclass over-rides the static  @@isArray property
 assert(new class extends Array {
   constructor() {return {}};
 });   // even if the subclass instance isn't an exotic array object (this is 
 an improvement over the current ES6 spec. which says that
   //isArray answers false in this case
 assert(new Proxy( [ ], { });  //because it's all done with property access, 
 no instance inspection required.
 
 (These want Array.isArray inside assert, of course.)

of course

 
 assert( ! new Int32Array(10));  //not array-like, just like ES5
 
 However, I think we should experiment with giving %TypedArrau% is true 
 valued @@isArray property.  I'm guessing that this change won't actually 
 break anything.
 
 Probably ok.
 
 the above proposal completely decouples Array.isArray from exotic array 
 object checking or any other direct instance inspection. Everything works at 
 the property access level and so is (by default) transparent to proxies and 
 completely controllable at the ES cod level.
 
 Righteous goal!
 
 /be
 

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


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-17 Thread Allen Wirfs-Brock

On Nov 17, 2014, at 2:30 PM, Allen Wirfs-Brock wrote:

 
 On Nov 17, 2014, at 11:06 AM, Brendan Eich wrote:
 
 Allen Wirfs-Brock wrote:
 ```js
 Array[Symbol.isArray]] = true;  //note, this is a constructor property, not 
 an Array.prototype property.
 
 Minomer, then -- how about Symbol.isArrayClass?
 
 perhaps, I have a negative reaction to including the work class but can 
 probably live with it.
 
 
 we also change Array.prototype.concat to do the above Array.isArray test 
 instead of using @@comcatSpreadable and change JSON.stringify to use this 
 test where it current checks for an exotic array object.
 
 Then we have the following:
 
 assert(Array.isArray( [ ] ));  //just like ES5
 assert( ! Array.isArray( Object.create(Array.prototype))); //just like ES5
 
 How so? True:
 
 js Array.isArray(Array.prototype)
 true
 js Array.isArray(Object.create(Array.prototype))
 false
 
 but constructor isn't shadowed:
 
 js Array.prototype.constructor
 function Array() {
   [native code]
 }
 js Object.create(Array.prototype).constructor
 function Array() {
   [native code]
 }
 
 Shit, you're right.  This is the hard case for legacy compat using this 
 technique. 
 
 I think I see a way to make this give the legacy answer, but I suspect I 
 can't make it give the same answer for
  Array.isArray(new Proxy(Object.create(Array.prototype), { }));
 May limiting the WTF=ness to that case isn't so bad.

OK, this should deal with the Object.create(Array.prototype) case

Array.isArray = function isArray(obj) {
   let constructor = obj.constructor;
   If (typeof constructor != 'function') return false;
   let construictorIs be Object.getOwnPropertyDescript(constructor,isArray);
   if (constructorIs) {
   //the constructor has an isArray property, so we'll assume it is a 
built-in Array constructor
   if (isOrdinaryObject(obj)) return false;  //The 
Object.create(Array.prototype) legacy compat. case.
   if (isProxy(obj)) return isArray(getProxyTarget(obj)); 
//Array.isArray(new Proxy(Object.create(Array.prototype), {}))
   //I'm not sure that the above line is really a compat. issue. I'd prefer 
to leave it out.
   }
   return !!constructor[Symbol.isArray];
}


It takes a little hackery to deal with the legacy 
Object.create(Array.prototype) cases but for ES6 subclasses and non-subclasses 
such as typed arrays it doesn't perform any exotic instance sniffing.

Allen


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


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-17 Thread Brendan Eich

Allen Wirfs-Brock wrote:

if (isProxy(obj)) return isArray(getProxyTarget(obj)); 
//Array.isArray(new Proxy(Object.create(Array.prototype), {}))
//I'm not sure that the above line is really a compat. issue. I'd 
prefer to leave it out.


Please do -- it contradicts the righteous goal.

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


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-17 Thread Tom Van Cutsem
2014-11-17 18:30 GMT+01:00 Allen Wirfs-Brock al...@wirfs-brock.com:


 But probing through the proxy as has been proposed is a terrible violation
 of the MOP API boundary and isn't generalizable to other built-ins that are
 dependent upon internal state. While a null handler proxy on a direct
 instance of Array would work under that design, a comparable Map.isMap or
 Promise.isPromise method would not.  Rather than a one-off hack I think we
 should use a new pattern that is generalizable:


If we can find consensus on this much more general pattern of type-testing
by using a symbol on the constructor, I'm all for it. +1!
I also think we don't want to special-case Proxies in the proposed
type-testing algorithm.

That said, if we cannot come to a consensus on this more generic form of
type-testing, I would still defend the position that Array.isArray merits
an exception (compared to Map.isMap/Promise.isPromise etc.) *precisely
because* Arrays were carefully defined not to depend on any special
instance state. In this scenario, repurposing the @@isConcatSpreadable
symbol seems like the most obvious thing to do (it currently feels terribly
ad-hoc, making it something more generic such as @@isArrayLike makes more
sense to me)

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


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-16 Thread Boris Zbarsky

On 11/16/14, 2:12 AM, Brendan Eich wrote:

Are you confident this change is web-compatible?


No, I said that up-thread already.  So there may be nothing to worry 
about here spec-wise for now.


-Boris


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


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-16 Thread Frankie Bagnardi
Consider when Array.isArray would be used.  In my experience, checks to see
if something is an array are used for:

 - deciding how to iterate it (for(;;) vs for..in, for example)
 - deciding if the output should be an array or plain object (e.g. lodash)
 - early errors, e.g. runtime typecheck errors

In all of these situations, I don't care if it is an actual per-spec exact
array, I care if I can use it like an array.  That's how Array.isArray will
likely be used, and if it runs into problems, then expect github to be full
of 'don't use Array.isArray' patches on many libraries, much like the
existing instanceof situation.





On Sun, Nov 16, 2014 at 11:20 AM, Boris Zbarsky bzbar...@mit.edu wrote:

 On 11/16/14, 2:12 AM, Brendan Eich wrote:

 Are you confident this change is web-compatible?


 No, I said that up-thread already.  So there may be nothing to worry about
 here spec-wise for now.

 -Boris



 ___
 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: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-16 Thread Tom Van Cutsem
2014-11-17 3:34 GMT+01:00 Frankie Bagnardi f.bagna...@gmail.com:

 Consider when Array.isArray would be used.  In my experience, checks to
 see if something is an array are used for:

  - deciding how to iterate it (for(;;) vs for..in, for example)


This is a good one. Here, again, a typical proxy-for-array would work as
intended, as the for(;;) loop just queries .length and properties named
0, 1, ... via standard [[Get]] access.

Can someone come up with a convincing example where a proxy-for-array would
*not* work as intended?
(convincing here means it doesn't involve a proxy that blatantly violates
the Array contract on purpose)

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


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-15 Thread David Bruant

Le 13/11/2014 17:29, Boris Zbarsky a écrit :

On 11/13/14, 6:44 AM, Andreas Rossberg wrote:

Well, the actual diabolic beast and universal foot gun in this example
is setPrototypeOf. ;)


Note that there is at least some discussion within Mozilla about 
trying to make the prototype of Object.prototype immutable (such that 
Object.getPrototypeOf(Object.prototype) is guaranteed to always return 
the same thing, modulo someone overriding Object.getPrototypeOf), 
along with a few other things along those lines.  See 
https://bugzilla.mozilla.org/show_bug.cgi?id=1052139.
This would result in objects which [[Prototype]] cannot be changed but 
which properties can be changed.
This is not possible per ES6 semantics I believe unless the object is a 
proxy (which setPrototypeOf trap throws unconditionally and forwards the 
rest to the target). Is it a satisfactory explanation? Should new 
primitives be added?



Whether this is web-compatible, we'll see.

I guess my above questions can wait the answer to this part.

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


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-15 Thread Allen Wirfs-Brock

On Nov 15, 2014, at 1:24 AM, David Bruant wrote:

 Le 13/11/2014 17:29, Boris Zbarsky a écrit :
 On 11/13/14, 6:44 AM, Andreas Rossberg wrote:
 Well, the actual diabolic beast and universal foot gun in this example
 is setPrototypeOf. ;)
 
 Note that there is at least some discussion within Mozilla about trying to 
 make the prototype of Object.prototype immutable (such that 
 Object.getPrototypeOf(Object.prototype) is guaranteed to always return the 
 same thing, modulo someone overriding Object.getPrototypeOf), along with a 
 few other things along those lines.  See 
 https://bugzilla.mozilla.org/show_bug.cgi?id=1052139.
 This would result in objects which [[Prototype]] cannot be changed but which 
 properties can be changed.
 This is not possible per ES6 semantics I believe unless the object is a proxy 
 (which setPrototypeOf trap throws unconditionally and forwards the rest to 
 the target). Is it a satisfactory explanation? Should new primitives be added?

Actually the ES6 semantics does allow for this.  The global object would have t 
be implemented as a new kind of implementation specific exotic object whose 
[[SetPrototypeOf]] internal method always returns false.

A Proxy would be required to self-host such an object using ES code, but at the 
implementation level a Proxy would not be required.

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


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-15 Thread Boris Zbarsky

On 11/15/14, 11:47 AM, Allen Wirfs-Brock wrote:

Actually the ES6 semantics does allow for this.  The global object would have t 
be implemented as a new kind of implementation specific exotic object whose 
[[SetPrototypeOf]] internal method always returns false.


That works for the global object (which is an exotic object anyway in 
browsers, because it has Web IDL branding of various sorts), but not for 
Object.prototype


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


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-15 Thread Brendan Eich

Boris Zbarsky wrote:

On 11/15/14, 11:47 AM, Allen Wirfs-Brock wrote:
- hide quoted text -- show quoted text -
Actually the ES6 semantics does allow for this.  The global object 
would have t be implemented as a new kind of implementation specific 
exotic object whose [[SetPrototypeOf]] internal method always returns 
false.


That works for the global object (which is an exotic object anyway in 
browsers, because it has Web IDL branding of various sorts), but not 
for Object.prototype


Perhaps a one-off exception?

Are you confident this change is web-compatible?

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


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-14 Thread Andrea Giammarchi
As quick parenthesis, I do hope the potentially evil code I've written will
be possible in the future, as universal solution to `undefined is not
defined` error in development code.

evil is never necessarily evil, going with prohibitionism won't make
anyone happy.

About `Array.isArray` though, I believe devs expect the Proxy to be
transparent, but again, for development or library sake, I expect
developers to be able to tell if there is some cellophane around their
objects.

Array.isArray(proxied) whould be true if the proxied object isArray, but
please consider give developers a way to understand if there is a proxy
around.

It won't be a good looking thing, but as it's needed internally, it might
be needed out there too.

Regards

On Thu, Nov 13, 2014 at 3:48 PM, David Bruant bruan...@gmail.com wrote:

  The best defense is Object.freeze(Object.prototype);
 No application worth considering needs to arbitrarily modify
 Object.prototype at an arbitrary point in time (or someone should bring a
 use case for discussion). It usually shouldn't and even if it does, it
 should do it at startup and freeze it afterwards.

 Le 13/11/2014 12:25, Andrea Giammarchi a écrit :

 well, Proxy can be a diabolic beast

  ```js
 Object.setPrototypeOf(
   Object.prototype,
   new Proxy(Object.prototype, evilPlan)
 )
 ```

  having no way to understand if an object is a Proxy looks like a footgun
 to me in the long term, for libraries, and code alchemists

 You're giving guns to people and try to evaluate how to defend from them.
 Consider not letting guns around the rooms ;-)

 David

  You indeed wrote that different Array methods need to know if there's a
 Proxy in there ... if dev cannot know the same via code they are unable
 again to subclass properly or replicate native behaviors behind magic
 internal checks.

  If there is a way and I'm missing it, then it's OK

  Regards








 On Thu, Nov 13, 2014 at 7:15 AM, Tom Van Cutsem tomvc...@gmail.com
 wrote:

 2014-11-12 23:49 GMT+01:00 Andrea Giammarchi andrea.giammar...@gmail.com
 :

 If Array.isArray should fail for non pure Arrays, can we have a
 Proxy.isProxy that never fails with proxies ?


  We ruled out `Proxy.isProxy` very early on in the design. It's
 antithetical to the desire of keeping proxies transparent. In general, we
 want to discourage type checks like you just wrote.

  If you're getting handed an object you don't trust and need very strong
 guarantees on its behavior, you'll need to make a copy. This is true
 regardless of proxies. In your example, even if the array is genuine, there
 may be some pointer alias to the array that can change the array at a later
 time.

  Regards,
 Tom




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


RE: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-14 Thread Domenic Denicola
From: es-discuss [mailto:es-discuss-boun...@mozilla.org] On Behalf Of Tom Van 
Cutsem

 Is the `length` invariant really the dominant meaning JS developers attribute 
 to Array.isArray? I think to most developers Array.isArray(obj) returning 
 true means that it's safe to call the array utilities (map, forEach, ...) on 
 obj, not so much that obj.length is special.

This is really interesting. It does argue for some kind of redefinition of 
Array.isArray to return is this an instance of some %ArrayPrototype% in some 
realm? That is very close to does the object have an @@isConcatSpreadable 
property, the main difference being that you can fake the latter via 
`myObj[Symbol.isConcatSpreadable] = true` while still not inheriting from any 
%ArrayPrototype%.

---

To me the most interesting question is how to create objects that get 
JSON-stringified as [], not {}. Some sort of symbol-based mechanism makes sense 
for that, IMO...

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


RE: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-14 Thread Michał Wadas
Hai.

Why not Symbol.isArray?

 To me the most interesting question is how to create objects that get
JSON-stringified as [], not {}. Some sort of symbol-based mechanism makes
sense for that, IMO...

toJSON method.

`JSON.stringify({toJSON: () = [2,3,4,5]})`
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-14 Thread Kevin Smith

 This is really interesting. It does argue for some kind of redefinition of
 Array.isArray to return is this an instance of some %ArrayPrototype% in
 some realm?


Yeah, my guess would be that if (Array.isArray(obj) === true), then the
user will infer that one or both of the following is true:

- It behaves as if it were created with an array literal (including the
length invariant and Array.prototype methods).
- It should be rendered (via JSON or console output) as if it were
created with an array literal.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-14 Thread Allen Wirfs-Brock

On Nov 13, 2014, at 5:02 PM, Brendan Eich wrote:

 Allen Wirfs-Brock wrote:
 We might redefine Array.isArray to be based upon testing for 
 @@isConcatSpreadable but that potentially would give different results for 
 legacy uses that did __proto__ hacking such as I mentioned in my previous 
 mote.
 
 How about we turn the @@ property into @@isArrayLike or @@isStronglyArrayLike 
 if you insist.

This could be done, but that property could pre-exist on Array prototype.  If 
it did, it would change the behavior (probably including the JSON.stringify 
behavior) of existing code that puts Array.prototype on its [[Prototype]] chain.

The definition of Array.isArray(obj) would be roughly:

1. Let isArray be ToBoolean(Get(obj, @@isArrayLike));
2. If isArray is true, then return true;
3. If obj is an exotic array object, then return true;
4. return false

Allen

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


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-14 Thread Allen Wirfs-Brock

On Nov 14, 2014, at 4:53 AM, Domenic Denicola wrote:

 From: es-discuss [mailto:es-discuss-boun...@mozilla.org] On Behalf Of Tom Van 
 Cutsem
 
 Is the `length` invariant really the dominant meaning JS developers 
 attribute to Array.isArray? I think to most developers Array.isArray(obj) 
 returning true means that it's safe to call the array utilities (map, 
 forEach, ...) on obj, not so much that obj.length is special.
 
 This is really interesting. It does argue for some kind of redefinition of 
 Array.isArray to return is this an instance of some %ArrayPrototype% in some 
 realm? That is very close to does the object have an @@isConcatSpreadable 
 property, the main difference being that you can fake the latter via 
 `myObj[Symbol.isConcatSpreadable] = true` while still not inheriting from any 
 %ArrayPrototype%.

What do you mean by is an instance of some %ArrayPrototype%? Do you mean that 
it has some %ArratPrototype% in it's prototype chain?  This is actually fairly 
hard to determine.  We look at trying to identify known prototypes independent 
of realm  for an earlier issue and rejected the possibility because it would 
require additional tragging of such prototypes.  Also, it wasn't clear who the 
concept could be extended to JS defined classes.

Allen



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


RE: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-14 Thread Domenic Denicola
From: Allen Wirfs-Brock [mailto:al...@wirfs-brock.com] 

 What do you mean by is an instance of some %ArrayPrototype%? Do you mean 
 that it has some %ArratPrototype% in it's prototype chain?

Yeah, more or less. A realm-independent instanceof. This makes sense also 
from the historical perspective that `Array.isArray` was meant to provide a 
cross-realm alternative to `instanceof Array`. (I believe that was the case; 
before my time.)

However as you pointed out in a related conversation this would not be 
backward-compatible, i.e. it would change the answer for code that does 
prototype munging.

 This is actually fairly hard to determine.  We look at trying to identify 
 known prototypes independent of realm  for an earlier issue and rejected the 
 possibility because it would require additional tragging of such prototypes.  
 Also, it wasn't clear who the concept could be extended to JS defined classes.

Right, good points. Probably not the way to go, indeed.

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


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-14 Thread Allen Wirfs-Brock

On Nov 14, 2014, at 11:41 AM, Domenic Denicola wrote:

 From: Allen Wirfs-Brock [mailto:al...@wirfs-brock.com] 
 
 What do you mean by is an instance of some %ArrayPrototype%? Do you mean 
 that it has some %ArratPrototype% in it's prototype chain?
 
 Yeah, more or less. A realm-independent instanceof. This makes sense also 
 from the historical perspective that `Array.isArray` was meant to provide a 
 cross-realm alternative to `instanceof Array`. (I believe that was the case; 
 before my time.)

No really, it was a way to expose a test of the [[Class]] internal property.  
That test wasn't dependent upon the [[Prototype]] chain.

Allen

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


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-14 Thread Tom Van Cutsem
2014-11-14 21:00 GMT+01:00 Allen Wirfs-Brock al...@wirfs-brock.com:

 On Nov 14, 2014, at 11:41 AM, Domenic Denicola wrote:

  Yeah, more or less. A realm-independent instanceof. This makes sense
 also from the historical perspective that `Array.isArray` was meant to
 provide a cross-realm alternative to `instanceof Array`. (I believe that
 was the case; before my time.)

 No really, it was a way to expose a test of the [[Class]] internal
 property.  That test wasn't dependent upon the [[Prototype]] chain.


I think what Domenic was saying is that Array.isArray used such a test
*because* instanceof Array didn't work reliably cross-realms. I too vaguely
recollect that reliable cross-realm instanceof Array testing was a
primary motivation for Array.isArray.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-14 Thread Brendan Eich

Tom Van Cutsem wrote:


No really, it was a way to expose a test of the [[Class]] internal
property.  That test wasn't dependent upon the [[Prototype]] chain.


I think what Domenic was saying is that Array.isArray used such a test 
*because* instanceof Array didn't work reliably cross-realms. I too 
vaguely recollect that reliable cross-realm instanceof Array testing 
was a primary motivation for Array.isArray.


Yes, that was Crock's stated motivation as I recall. Here's a 2003-era 
post from Doug:


https://groups.google.com/forum/#!msg/comp.lang.javascript/XTWYCOwC96I/70rNoQ3L-xoJ

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


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-14 Thread Tom Van Cutsem
2014-11-13 22:35 GMT+01:00 Tom Van Cutsem tomvc...@gmail.com:

 My intuition is that Array.isArray is often used to branch based on
 whether code received just one versus a collection of values. E.g. a
 function may take a single parameter that can be bound to either a single
 value or a collection of values, and treat a collection of values
 differently. In fact, that is essentially what Array.prototype.concat does:
 if the argument is an array, splice its values, otherwise, don't splice.
 This has nothing to do with `length` magic. The same goes for
 JSON.stringify (serialize as [] vs {}).


Amusingly, not only does JSON.stringify(value, replacer, space) branch on
the type of its `value` argument (to serialize as [] vs {}), it
apparently also type-tests its `replacer` argument, which can either be a
function or an array. If it's an array, it serves as a whitelist of the
properties that can appear in the output. While it's unlikely anyone would
ever want to pass a proxy-for-array as a JSON whitelist, JSON.stringify is
an example of the kind of type-testing I had in mind to simply distinguish
whether one of its parameters is just one value vs. a collection of values.
For such functions, there would be no harm in treating proxies-for-arrays
as arrays.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-14 Thread Jeremy Martin
I don't have the data to back this up, but I would argue that the developer
community has essentially adopted `Array.isArray()` as a sane replacement
for `Object.prototype.toString.call(maybeArray) === '[object Array]'`.

I realize this forum doesn't have the luxury of *not* considering the
nuances between a value having the right [[Class] property vs. having
Array.prototype in the chain vs. having an exotic length property, etc.,
but I would at least suggest that the consumers of `Array.isArray()` are
largely just concerned with whether or not they can do everything with a
particular value that they could do if it were an actual array, while
maintaining equal code semantics.

Allen's previous comments:

Proxies are not transparent forwarders!  In particular their default
 handling of the `this` value on method invokes will break any built-in
 method that needs to access internal slots of an object.


...lead me to believe that this isn't the case for proxified Arrays, so I'd
have to reverse my earlier position, as `Array.isArray(proxifiedArray)`
evaluating to true just seems likely to break code.


On Fri, Nov 14, 2014 at 3:36 PM, Brendan Eich bren...@mozilla.org wrote:

 Tom Van Cutsem wrote:


 No really, it was a way to expose a test of the [[Class]] internal
 property.  That test wasn't dependent upon the [[Prototype]] chain.


 I think what Domenic was saying is that Array.isArray used such a test
 *because* instanceof Array didn't work reliably cross-realms. I too vaguely
 recollect that reliable cross-realm instanceof Array testing was a
 primary motivation for Array.isArray.


 Yes, that was Crock's stated motivation as I recall. Here's a 2003-era
 post from Doug:

 https://groups.google.com/forum/#!msg/comp.lang.javascript/XTWYCOwC96I/
 70rNoQ3L-xoJ

 /be

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




-- 
Jeremy Martin
661.312.3853
http://devsmash.com
@jmar777
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-14 Thread Tom Van Cutsem
2014-11-14 21:52 GMT+01:00 Jeremy Martin jmar...@gmail.com:

 Allen's previous comments:

 Proxies are not transparent forwarders!  In particular their default
 handling of the `this` value on method invokes will break any built-in
 method that needs to access internal slots of an object.


 ...lead me to believe that this isn't the case for proxified Arrays, so
 I'd have to reverse my earlier position, as `Array.isArray(proxifiedArray)`
 evaluating to true just seems likely to break code.


For the particular case of Arrays though, because Array methods were
carefully specified to be generic (i.e. to also work on non-array objects),
they will work just fine on proxies-for-arrays:

var p = new Proxy([1,2,3] , {} );
var a = p.map(function(x) { return x + 1; });
console.log(a); // [2,3,4]

So, of all the exotic objects in the ES and WebIDL specs, Arrays are
probably one of the few exceptions where a Proxy wrapper *is* transparent
by default.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-14 Thread Brendan Eich

Tom Van Cutsem wrote:
2014-11-14 21:52 GMT+01:00 Jeremy Martin jmar...@gmail.com 
mailto:jmar...@gmail.com:


Allen's previous comments:

Proxies are not transparent forwarders!  In particular their
default handling of the `this` value on method invokes will
break any built-in method that needs to access internal
slots of an object.


...lead me to believe that this isn't the case for proxified
Arrays, so I'd have to reverse my earlier position, as
`Array.isArray(proxifiedArray)` evaluating to true just seems
likely to break code.


For the particular case of Arrays though, because Array methods were 
carefully specified to be generic (i.e. to also work on non-array 
objects), they will work just fine on proxies-for-arrays:


var p = new Proxy([1,2,3] , {} );
var a = p.map(function(x) { return x + 1; });
console.log(a); // [2,3,4]

So, of all the exotic objects in the ES and WebIDL specs, Arrays are 
probably one of the few exceptions where a Proxy wrapper *is* 
transparent by default.


Right.

There is no all-or-nothing solution. Allen's words applie to exceptions 
to the rule. Arrays and well-written proxies for them fit in the rule. 
Jeremy, what do you say?


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


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-14 Thread Jeremy Martin
(Mostly) transparent forwarding seems to be one of the more compelling and
generally useful characteristics of Proxies.  I have to lean heavily on the
deeper knowledge of the group here, but *if* `new Proxy([], {})` otherwise
behaves like a bonafide array when you treat it like one, then it would be
a pity to lose the ability to take advantage of that over `Array.isArray()`
resolving to false.  *If* transparent forwarding is an intended feature of
proxied arrays, then I'd argue it's far too common of a test to discount .
But again, I can't answer those ifs. :)

On Fri, Nov 14, 2014 at 4:54 PM, Brendan Eich bren...@mozilla.org wrote:

 Tom Van Cutsem wrote:

 2014-11-14 21:52 GMT+01:00 Jeremy Martin jmar...@gmail.com mailto:
 jmar...@gmail.com:


 Allen's previous comments:

 Proxies are not transparent forwarders!  In particular their
 default handling of the `this` value on method invokes will
 break any built-in method that needs to access internal
 slots of an object.


 ...lead me to believe that this isn't the case for proxified
 Arrays, so I'd have to reverse my earlier position, as
 `Array.isArray(proxifiedArray)` evaluating to true just seems
 likely to break code.


 For the particular case of Arrays though, because Array methods were
 carefully specified to be generic (i.e. to also work on non-array objects),
 they will work just fine on proxies-for-arrays:

 var p = new Proxy([1,2,3] , {} );
 var a = p.map(function(x) { return x + 1; });
 console.log(a); // [2,3,4]

 So, of all the exotic objects in the ES and WebIDL specs, Arrays are
 probably one of the few exceptions where a Proxy wrapper *is* transparent
 by default.


 Right.

 There is no all-or-nothing solution. Allen's words applie to exceptions to
 the rule. Arrays and well-written proxies for them fit in the rule. Jeremy,
 what do you say?

 /be




-- 
Jeremy Martin
661.312.3853
http://devsmash.com
@jmar777
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-13 Thread Andrea Giammarchi
well, Proxy can be a diabolic beast

```js
Object.setPrototypeOf(
  Object.prototype,
  new Proxy(Object.prototype, evilPlan)
)
```

having no way to understand if an object is a Proxy looks like a footgun to
me in the long term, for libraries, and code alchemists

You indeed wrote that different Array methods need to know if there's a
Proxy in there ... if dev cannot know the same via code they are unable
again to subclass properly or replicate native behaviors behind magic
internal checks.

If there is a way and I'm missing it, then it's OK

Regards








On Thu, Nov 13, 2014 at 7:15 AM, Tom Van Cutsem tomvc...@gmail.com wrote:

 2014-11-12 23:49 GMT+01:00 Andrea Giammarchi andrea.giammar...@gmail.com
 :

 If Array.isArray should fail for non pure Arrays, can we have a
 Proxy.isProxy that never fails with proxies ?


 We ruled out `Proxy.isProxy` very early on in the design. It's
 antithetical to the desire of keeping proxies transparent. In general, we
 want to discourage type checks like you just wrote.

 If you're getting handed an object you don't trust and need very strong
 guarantees on its behavior, you'll need to make a copy. This is true
 regardless of proxies. In your example, even if the array is genuine, there
 may be some pointer alias to the array that can change the array at a later
 time.

 Regards,
 Tom

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


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-13 Thread Andreas Rossberg
On 13 November 2014 12:25, Andrea Giammarchi
andrea.giammar...@gmail.com wrote:
 well, Proxy can be a diabolic beast

 ```js
 Object.setPrototypeOf(
   Object.prototype,
   new Proxy(Object.prototype, evilPlan)
 )
 ```

 having no way to understand if an object is a Proxy looks like a footgun to
 me in the long term, for libraries, and code alchemists

Well, the actual diabolic beast and universal foot gun in this example
is setPrototypeOf. ;)

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


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-13 Thread Andrea Giammarchi
Same would be reassigning any prototype but it was just to make the
diabolic point... also yeah, sPO is powerful, that's why we love it!

( it's also way less diabolic than any __proto__ string floating around
;) )

On Thu, Nov 13, 2014 at 11:44 AM, Andreas Rossberg rossb...@google.com
wrote:

 On 13 November 2014 12:25, Andrea Giammarchi
 andrea.giammar...@gmail.com wrote:
  well, Proxy can be a diabolic beast
 
  ```js
  Object.setPrototypeOf(
Object.prototype,
new Proxy(Object.prototype, evilPlan)
  )
  ```
 
  having no way to understand if an object is a Proxy looks like a footgun
 to
  me in the long term, for libraries, and code alchemists

 Well, the actual diabolic beast and universal foot gun in this example
 is setPrototypeOf. ;)

 /Andreas

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


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-13 Thread David Bruant

The best defense is Object.freeze(Object.prototype);
No application worth considering needs to arbitrarily modify 
Object.prototype at an arbitrary point in time (or someone should bring 
a use case for discussion). It usually shouldn't and even if it does, it 
should do it at startup and freeze it afterwards.


Le 13/11/2014 12:25, Andrea Giammarchi a écrit :

well, Proxy can be a diabolic beast

```js
Object.setPrototypeOf(
  Object.prototype,
  new Proxy(Object.prototype, evilPlan)
)
```

having no way to understand if an object is a Proxy looks like a 
footgun to me in the long term, for libraries, and code alchemists
You're giving guns to people and try to evaluate how to defend from 
them. Consider not letting guns around the rooms ;-)


David

You indeed wrote that different Array methods need to know if there's 
a Proxy in there ... if dev cannot know the same via code they are 
unable again to subclass properly or replicate native behaviors behind 
magic internal checks.


If there is a way and I'm missing it, then it's OK

Regards








On Thu, Nov 13, 2014 at 7:15 AM, Tom Van Cutsem tomvc...@gmail.com 
mailto:tomvc...@gmail.com wrote:


2014-11-12 23:49 GMT+01:00 Andrea Giammarchi
andrea.giammar...@gmail.com mailto:andrea.giammar...@gmail.com:

If Array.isArray should fail for non pure Arrays, can we
have a Proxy.isProxy that never fails with proxies ?


We ruled out `Proxy.isProxy` very early on in the design. It's
antithetical to the desire of keeping proxies transparent. In
general, we want to discourage type checks like you just wrote.

If you're getting handed an object you don't trust and need very
strong guarantees on its behavior, you'll need to make a copy.
This is true regardless of proxies. In your example, even if the
array is genuine, there may be some pointer alias to the array
that can change the array at a later time.

Regards,
Tom




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


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-13 Thread Boris Zbarsky

On 11/13/14, 6:44 AM, Andreas Rossberg wrote:

Well, the actual diabolic beast and universal foot gun in this example
is setPrototypeOf. ;)


Note that there is at least some discussion within Mozilla about trying 
to make the prototype of Object.prototype immutable (such that 
Object.getPrototypeOf(Object.prototype) is guaranteed to always return 
the same thing, modulo someone overriding Object.getPrototypeOf), along 
with a few other things along those lines.  See 
https://bugzilla.mozilla.org/show_bug.cgi?id=1052139.


Whether this is web-compatible, we'll see.

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


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-13 Thread Allen Wirfs-Brock

On Nov 12, 2014, at 12:12 PM, Tom Van Cutsem tomvc...@gmail.com wrote:

 2014-11-12 19:53 GMT+01:00 Rick Waldron waldron.r...@gmail.com:
 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 

Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-13 Thread Allen Wirfs-Brock

On Nov 12, 2014, at 11:58 AM, Jeremy Martin wrote:

 My opinion is that array testing is fundamental to core JS and is worth the 
 exception.
 
 Knowing that Array.isArray() tests fail for proxies, I'd be afraid to ever 
 create a Proxy for an array that I don't control the complete lifecycle of. 
 That seems to critically inhibit the usefulness of Proxies, especially when 
 transparency seems to have been an intended characteristic of them going all 
 the way back to the strawman days.

Proxies are not transparent forwarders!  In particular their default handling 
of the `this` value on method invokes will break any built-in method that needs 
to access internal slots of an object.

```js
var p = new Proxy(new Array, {});
```
will give you an object that will fail on serval of the Array.prototype methods.

It is even worse for other built-ins such as Map or the typed array 
constructors.

Allen

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


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-13 Thread Tom Van Cutsem
2014-11-13 20:31 GMT+01:00 Allen Wirfs-Brock al...@wirfs-brock.com:


 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.


Is the `length` invariant really the dominant meaning JS developers
attribute to Array.isArray? I think to most developers Array.isArray(obj)
returning true means that it's safe to call the array utilities (map,
forEach, ...) on obj, not so much that obj.length is special.

My intuition is that Array.isArray is often used to branch based on whether
code received just one versus a collection of values. E.g. a function may
take a single parameter that can be bound to either a single value or a
collection of values, and treat a collection of values differently. In
fact, that is essentially what Array.prototype.concat does: if the argument
is an array, splice its values, otherwise, don't splice. This has nothing
to do with `length` magic. The same goes for JSON.stringify (serialize as
[] vs {}).

Now, if we take the meaning of Array.isArray to be supports the
Array.prototype utility methods, a proxy-for-array may of course expose a
totally different API, leading a client that expects to be able to use the
Array.prototype methods to fail. But this foregoes the fact that for
virtually all practical use cases of proxies, proxy authors will not do
this. They want to be able to wrap objects, intercept some things, but
mostly faithfully forward those operations to the wrapped target. It would
be rare for a proxy to change the API of the thing it wraps. Indeed, the
whole point of proxies is to be able to intercept operations without
modifying client code.

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


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-13 Thread Brendan Eich

Allen Wirfs-Brock wrote:
We might redefine Array.isArray to be based upon testing for 
@@isConcatSpreadable but that potentially would give different results 
for legacy uses that did __proto__ hacking such as I mentioned in my 
previous mote.


How about we turn the @@ property into @@isArrayLike or 
@@isStronglyArrayLike if you insist.


Now, if we take the meaning of Array.isArray to be supports the 
Array.prototype utility methods, a proxy-for-array may of course 
expose a totally different API, leading a client that expects to be 
able to use the Array.prototype methods to fail. But this foregoes 
the fact that for virtually all practical use cases of proxies, proxy 
authors will not do this. They want to be able to wrap objects, 
intercept some things, but mostly faithfully forward those operations 
to the wrapped target. It would be rare for a proxy to change the API 
of the thing it wraps. Indeed, the whole point of proxies is to be 
able to intercept operations without modifying client code.


Certainly if you use a proxy to define a virtual object, to self-host, 
spec-defined exotic objects or to implement DOM objects you just 
aren't transparently wrapping the target object...


I think at the root of this is that many JS programmer don't really 
understand what is (or isn't special about Array instances and that 
Array.isArray may have just added to the confusion.


That may be, but (part of) our job is to help them. So progressively 
refining the meaning via @@isArrayLike seems winning.


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


Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-12 Thread Axel Rauschmayer
The subject is a SpiderMonkey bug.

Is that really desirable? Doesn’t it invalidate the Proxy’s role as an 
interceptor?

-- 
Dr. Axel Rauschmayer
a...@rauschma.de
rauschma.de



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


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-12 Thread Tom Van Cutsem
I agree with your sentiment. I have previously advocated that Array.isArray
should be transparent for proxies. My harmony-reflect shim explicitly
differs from the spec on this point because people using the shim
spontaneously reported this as the expected behaviour and thought it was a
bug that Array.isArray didn't work transparently on proxies.

As far as I can remember, the argument against making Array.isArray
transparent is that it's ad hoc and doesn't generalize to other types /
type tests. My opinion is that array testing is fundamental to core JS and
is worth the exception.

Regards,
Tom

2014-11-12 17:04 GMT+01:00 Axel Rauschmayer a...@rauschma.de:

 The subject is a SpiderMonkey bug.

 Is that really desirable? Doesn’t it invalidate the Proxy’s role as an
 interceptor?

 --
 Dr. Axel Rauschmayer
 a...@rauschma.de
 rauschma.de




 ___
 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: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-12 Thread David Bruant

Le 12/11/2014 17:23, Tom Van Cutsem a écrit :
I agree with your sentiment. I have previously advocated that 
Array.isArray should be transparent for proxies. My harmony-reflect 
shim explicitly differs from the spec on this point because people 
using the shim spontaneously reported this as the expected behaviour 
and thought it was a bug that Array.isArray didn't work transparently 
on proxies.

For reference https://github.com/tvcutsem/harmony-reflect/issues/13

As far as I can remember, the argument against making Array.isArray 
transparent is that it's ad hoc and doesn't generalize to other types 
/ type tests. My opinion is that array testing is fundamental to core 
JS and is worth the exception.

Agreed. Author usability should trump language purity.

David



Regards,
Tom

2014-11-12 17:04 GMT+01:00 Axel Rauschmayer a...@rauschma.de 
mailto:a...@rauschma.de:


The subject is a SpiderMonkey bug.

Is that really desirable? Doesn’t it invalidate the Proxy’s role
as an interceptor?

-- 
Dr. Axel Rauschmayer

a...@rauschma.de mailto:a...@rauschma.de
rauschma.de http://rauschma.de




___
es-discuss mailing list
es-discuss@mozilla.org mailto: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: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-12 Thread Rick Waldron
On Wed, Nov 12, 2014 at 11:23 AM, Tom Van Cutsem tomvc...@gmail.com wrote:

 My opinion is that array testing is fundamental to core JS and is worth
 the exception.


I agree and I want to know if you think this is worth revisiting once more?
Next meeting's agenda?

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


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-12 Thread Tom Van Cutsem
2014-11-12 19:53 GMT+01:00 Rick Waldron waldron.r...@gmail.com:

 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.

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


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-12 Thread Kevin Smith
In general, it appears that SM unwraps proxies so that internal slot access
is transparently forwarded.  I don't see any such unwrapping in the ES spec
though.  I assume that the spec is correct?
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-12 Thread Rick Waldron
On Wed, Nov 12, 2014 at 2:12 PM, Tom Van Cutsem tomvc...@gmail.com wrote:

 2014-11-12 19:53 GMT+01:00 Rick Waldron waldron.r...@gmail.com:

 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.


Done https://github.com/tc39/agendas/blob/master/2014/11.md

Rick



 regards,
 Tom

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


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-12 Thread Jeremy Martin

 My opinion is that array testing is fundamental to core JS and is worth
 the exception.


Knowing that Array.isArray() tests fail for proxies, I'd be afraid to ever
create a Proxy for an array that I don't control the complete lifecycle of.
That seems to critically inhibit the usefulness of Proxies, especially when
transparency seems to have been an intended characteristic of them going
all the way back to the strawman days.

On Wed, Nov 12, 2014 at 2:37 PM, Kevin Smith zenpars...@gmail.com wrote:

 In general, it appears that SM unwraps proxies so that internal slot
 access is transparently forwarded.  I don't see any such unwrapping in the
 ES spec though.  I assume that the spec is correct?

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




-- 
Jeremy Martin
661.312.3853
http://devsmash.com
@jmar777
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-12 Thread Andrea Giammarchi
If Array.isArray should fail for non pure Arrays, can we have a
Proxy.isProxy that never fails with proxies ?

At least this would give a better idea on what's eventually going on:

```js
if (Array.isArray(obj)  !Proxy.isProxy(obj)) {
  // ... ok, pure Array, no magic wrappers
}
```

Regards



On Wed, Nov 12, 2014 at 6:47 PM, David Bruant bruan...@gmail.com wrote:

  Le 12/11/2014 17:23, Tom Van Cutsem a écrit :

 I agree with your sentiment. I have previously advocated that
 Array.isArray should be transparent for proxies. My harmony-reflect shim
 explicitly differs from the spec on this point because people using the
 shim spontaneously reported this as the expected behaviour and thought it
 was a bug that Array.isArray didn't work transparently on proxies.

 For reference https://github.com/tvcutsem/harmony-reflect/issues/13

  As far as I can remember, the argument against making Array.isArray
 transparent is that it's ad hoc and doesn't generalize to other types /
 type tests. My opinion is that array testing is fundamental to core JS and
 is worth the exception.

 Agreed. Author usability should trump language purity.

 David


  Regards,
 Tom

 2014-11-12 17:04 GMT+01:00 Axel Rauschmayer a...@rauschma.de:

  The subject is a SpiderMonkey bug.

  Is that really desirable? Doesn’t it invalidate the Proxy’s role as an
 interceptor?

   --
 Dr. Axel Rauschmayer
 a...@rauschma.de
 rauschma.de




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




 ___
 es-discuss mailing 
 listes-discuss@mozilla.orghttps://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: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-12 Thread Tom Van Cutsem
2014-11-12 20:37 GMT+01:00 Kevin Smith zenpars...@gmail.com:

 In general, it appears that SM unwraps proxies so that internal slot
 access is transparently forwarded.  I don't see any such unwrapping in the
 ES spec though.  I assume that the spec is correct?


This auto-unwrapping for internal slots used to be part of an early
iteration of direct proxies 
http://wiki.ecmascript.org/doku.php?id=harmony:direct_proxies#wrapping_irregular_objects
but was not carried over into the ES6 spec. IIRC, mainly because just
forwarding any internal slot access endangers the encapsulation properties
of membrane-like use cases.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-12 Thread Tom Van Cutsem
2014-11-12 23:49 GMT+01:00 Andrea Giammarchi andrea.giammar...@gmail.com:

 If Array.isArray should fail for non pure Arrays, can we have a
 Proxy.isProxy that never fails with proxies ?


We ruled out `Proxy.isProxy` very early on in the design. It's antithetical
to the desire of keeping proxies transparent. In general, we want to
discourage type checks like you just wrote.

If you're getting handed an object you don't trust and need very strong
guarantees on its behavior, you'll need to make a copy. This is true
regardless of proxies. In your example, even if the array is genuine, there
may be some pointer alias to the array that can change the array at a later
time.

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


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-12 Thread Andreas Rossberg
On 12 November 2014 17:23, Tom Van Cutsem tomvc...@gmail.com wrote:
 My opinion is that array testing is fundamental to core JS and is
 worth the exception.

This change would only make sense if we also were to special-case all
other places in the spec that currently say if O is an exotic Array
object, ... to magically handle proxies. Otherwise, all you get is a
predicate that gives a misleading result.

However, I don't think we want to special-case all those places. That
would put us on a very slippery slope.

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


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-12 Thread Tom Van Cutsem
2014-11-12 20:53 GMT+01:00 Rick Waldron waldron.r...@gmail.com:


 Done https://github.com/tc39/agendas/blob/master/2014/11.md


Thanks. A related point: my harmony-reflect shim also patches
Array.prototype.concat such that it recognizes proxies-for-arrays and will
splice their elements (rather than adding the proxy as a single element to
the target array).

In ES6, this may not be necessary since a proxy could implement
@@isConcatSpreadable (see 
http://people.mozilla.org/~jorendorff/es6-draft.html#sec-array.prototype.concat
step 9.b)

However, looking at IsConcatSpreadable 
http://people.mozilla.org/~jorendorff/es6-draft.html#sec-isconcatspreadable
step 5, you'll notice it explicitly tests for Arrays. *If* we decide that
Array.isArray should return `true` for proxies-for-arrays, *then* I think
we should relax this step 5 to also return `true` for proxies-for-arrays,
on the grounds of consistency and principle-of-least-surprise.

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


Re: Array.isArray(new Proxy([], {})) should be false (Bug 1096753)

2014-11-12 Thread Tom Van Cutsem
2014-11-13 8:18 GMT+01:00 Andreas Rossberg rossb...@google.com:

 On 12 November 2014 17:23, Tom Van Cutsem tomvc...@gmail.com wrote:
  My opinion is that array testing is fundamental to core JS and is
  worth the exception.

 This change would only make sense if we also were to special-case all
 other places in the spec that currently say if O is an exotic Array
 object, ... to magically handle proxies. Otherwise, all you get is a
 predicate that gives a misleading result.


Yes, good point. See my just-recent post on Array.prototype.concat.


 However, I don't think we want to special-case all those places. That
 would put us on a very slippery slope.


A cursory look at the spec reveals the following built-ins that test for
exotic Arrays:

- Array.isArray
- Array.prototype.concat
- Array.prototype.filter
- Array.prototype.map
- Array.prototype.slice
- Array.prototype.splice
- JSON.parse
- JSON.stringify
- Object.prototype.toString

filter, map, slice and splice didn't used to test for arrays in ES5. They
seem to test for arrays such that the new array they create derives from
the same realm. This can probably be made to work with proxies-for-arrays,
but I'm not sure it is necessary or desirable.

For JSON.stringify, the question is whether a proxy-for-array should
serialize as [] vs {}. Obviously, if Array.isArray(proxyForArray), I
would expect it to serialize as [].

For toString, proxies could still implement @@toStringTag to be able to
intercept that call. At this point, I believe
Object.prototype.toString.call(proxyForArray) would return [object
Object].

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