Re: Re: Proxy handler.has() does not have a receiver argument?

2019-11-22 Thread #!/JoePea
I forgot to add, this even works with builtin scenarios like Custom
Elements,

```js
class MyEl extends mix(HTMLButtonElement, One, Two, Three) { /* ... */ }
customElements.define('my-el', MyEl)
```

On Fri, Nov 22, 2019 at 9:36 AM #!/JoePea  wrote:

> HI Cyril, thanks for pointing that out! I know about those, I've been
> using class-factory mixins for a while now. But the problem with them is
> having to wrap all your classes in a function, which gets much more painful
> in TypeScript with all the type-annotation boilerplate that is required.
>
> For example, here's a boilerplate-heavy mixin of mine:
>
> - Header:
> https://github.com/infamous/infamous/blob/develop/src/core/ImperativeBase.ts#L55
> - Footer:
> https://github.com/infamous/infamous/blob/develop/src/core/ImperativeBase.ts#L615
> - Mixin helper application (provides mixin result caching, deduplication,
> Symbol.hasInstance, etc):
> https://github.com/infamous/infamous/blob/develop/src/core/ImperativeBase.ts#L662
> - The type system that I imported from my lowclass lib:
> https://github.com/infamous/infamous/blob/develop/src/core/ImperativeBase.ts#L2
>
> Multiple inheritance with Proxies actually turns out very easy to type in
> TypeScript, and a lot more convenient than class factories. So, given a set
> of regular classes,
>
> ```js
> class One {
>   doOne() { /* ... */ }
> }
>
> class Two {
>   doTwo() { /* ... */ }
> }
>
> class Three {
>   doThree() { /* ... */ }
> }
> ```
>
> a Proxy-based multiple inheritance system makes the composition super
> easy, clean, and simple. We can convert the previous example into:
>
> ```js
> import mix from './mix'
>
> class One {
>   doOne() { /* ... */ }
> }
>
> class Two {
>   doTwo() { /* ... */ }
> }
>
> class Three extends mix(One, Two) {
>   doThree() { /* ... */ }
>   doAll() {
> this.doOne()
> this.doTwo()
> this.doThree()
>   }
> }
> ```
>
> All without touching the original source of the `One` and `Two` classes.
> How convenient, and easier to read and look at!
>
> My particular implementation will allow to call individual constructors
> with specific args, unlike the class-factory mixins. For example,
>
> ```js
> import mix from './mix'
>
> class One {
>   constructor(arg1, arg2) {/*...*/}
>   doOne() { /* ... */ }
> }
>
> class Two {
>   constructor(arg3) {/*...*/}
>   doTwo() { /* ... */ }
> }
>
> class Three extends mix(One, Two) {
>   constructor(arg1, arg2, arg3) {
> this.callConstructor(One, arg1, arg2)
> this.callConstructor(Two, arg3)
>   }
>   doThree() { /* ... */ }
>   doAll() {
> this.doOne()
> this.doTwo()
> this.doThree()
>   }
> }
> ```
>
> At the moment I'm looking to convert from my Proxies-on-prototypes
> implementation to Proxies-on-instances so that things like `in` operator
> will work, and implementation will be simpler and easier. Otherwise if the
> `has` trap had a `receiver` parameter, then I could stick with the
> Proxies-on-prototypes version which would be more efficient (the Proxy
> would be re-used on the prototype chain instead of being created once per
> instance).
>
> Would it be worth adding a `receiver` parameter to the `has` trap in the
> specs? Seems like it would be totally backwards compatible, because current
> code that doesn't rely on it could continue not relying on it oblivious to
> the new parameter.
>
> All the best,
> - Joe
>
> On Fri, Nov 22, 2019 at 3:55 AM Cyril Auburtin 
> wrote:
>
>> It's not answering your issue with Proxy but more about multiple
>> inheritance
>>
>> It can be solved in a static way:
>> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#Mix-ins
>>
>> Concrete example here:
>> https://github.com/pepabo/gmopg/blob/master/src/gmopg.ts#L10
>>
>> On Fri, Nov 22, 2019 at 4:23 AM #!/JoePea  wrote:
>>
>>> After messing with Proxy-on-prototypes for two days, I've just come to
>>> the conclusion that I probably need to have Proxies on this (the
>>> receiver) returned from constructors to achieve what I want. At least,
>>> it's much easier to code it that way. I think it'd be nice to have
>>> receiver on all inheritance-related traps. That might make some things
>>> easier.
>>>
>>> On Thu, Nov 21, 2019 at 2:55 PM #!/JoePea  wrote:
>>> >
>>> > I really thing that because `has` is about detecting inherited
>>> > properties, the `receiver` parameter should be included. For things
>>> > like `ownKeys`, which are not about inheritance, then yeah, let's not
>>> > add receiver there.
>>> >
>>> > I'm trying to implement my own multiple inheritance, but now I
>>> > stumbled on how to make it send back true for inherited keys when I
>>> > need to fork the lookup based on instances that are `WeakMap`ed to the
>>> > `receiver`.
>>> ___
>>> es-discuss mailing list
>>> es-discuss@mozilla.org
>>> https://mail.mozilla.org/listinfo/es-discuss
>>>
>>
___
es-discuss mailing list
es-discuss@mozilla.org

Re: Re: Proxy handler.has() does not have a receiver argument?

2019-11-22 Thread #!/JoePea
HI Cyril, thanks for pointing that out! I know about those, I've been using
class-factory mixins for a while now. But the problem with them is having
to wrap all your classes in a function, which gets much more painful in
TypeScript with all the type-annotation boilerplate that is required.

For example, here's a boilerplate-heavy mixin of mine:

- Header:
https://github.com/infamous/infamous/blob/develop/src/core/ImperativeBase.ts#L55
- Footer:
https://github.com/infamous/infamous/blob/develop/src/core/ImperativeBase.ts#L615
- Mixin helper application (provides mixin result caching, deduplication,
Symbol.hasInstance, etc):
https://github.com/infamous/infamous/blob/develop/src/core/ImperativeBase.ts#L662
- The type system that I imported from my lowclass lib:
https://github.com/infamous/infamous/blob/develop/src/core/ImperativeBase.ts#L2

Multiple inheritance with Proxies actually turns out very easy to type in
TypeScript, and a lot more convenient than class factories. So, given a set
of regular classes,

```js
class One {
  doOne() { /* ... */ }
}

class Two {
  doTwo() { /* ... */ }
}

class Three {
  doThree() { /* ... */ }
}
```

a Proxy-based multiple inheritance system makes the composition super easy,
clean, and simple. We can convert the previous example into:

```js
import mix from './mix'

class One {
  doOne() { /* ... */ }
}

class Two {
  doTwo() { /* ... */ }
}

class Three extends mix(One, Two) {
  doThree() { /* ... */ }
  doAll() {
this.doOne()
this.doTwo()
this.doThree()
  }
}
```

All without touching the original source of the `One` and `Two` classes.
How convenient, and easier to read and look at!

My particular implementation will allow to call individual constructors
with specific args, unlike the class-factory mixins. For example,

```js
import mix from './mix'

class One {
  constructor(arg1, arg2) {/*...*/}
  doOne() { /* ... */ }
}

class Two {
  constructor(arg3) {/*...*/}
  doTwo() { /* ... */ }
}

class Three extends mix(One, Two) {
  constructor(arg1, arg2, arg3) {
this.callConstructor(One, arg1, arg2)
this.callConstructor(Two, arg3)
  }
  doThree() { /* ... */ }
  doAll() {
this.doOne()
this.doTwo()
this.doThree()
  }
}
```

At the moment I'm looking to convert from my Proxies-on-prototypes
implementation to Proxies-on-instances so that things like `in` operator
will work, and implementation will be simpler and easier. Otherwise if the
`has` trap had a `receiver` parameter, then I could stick with the
Proxies-on-prototypes version which would be more efficient (the Proxy
would be re-used on the prototype chain instead of being created once per
instance).

Would it be worth adding a `receiver` parameter to the `has` trap in the
specs? Seems like it would be totally backwards compatible, because current
code that doesn't rely on it could continue not relying on it oblivious to
the new parameter.

All the best,
- Joe

On Fri, Nov 22, 2019 at 3:55 AM Cyril Auburtin 
wrote:

> It's not answering your issue with Proxy but more about multiple
> inheritance
>
> It can be solved in a static way:
> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#Mix-ins
>
> Concrete example here:
> https://github.com/pepabo/gmopg/blob/master/src/gmopg.ts#L10
>
> On Fri, Nov 22, 2019 at 4:23 AM #!/JoePea  wrote:
>
>> After messing with Proxy-on-prototypes for two days, I've just come to
>> the conclusion that I probably need to have Proxies on this (the
>> receiver) returned from constructors to achieve what I want. At least,
>> it's much easier to code it that way. I think it'd be nice to have
>> receiver on all inheritance-related traps. That might make some things
>> easier.
>>
>> On Thu, Nov 21, 2019 at 2:55 PM #!/JoePea  wrote:
>> >
>> > I really thing that because `has` is about detecting inherited
>> > properties, the `receiver` parameter should be included. For things
>> > like `ownKeys`, which are not about inheritance, then yeah, let's not
>> > add receiver there.
>> >
>> > I'm trying to implement my own multiple inheritance, but now I
>> > stumbled on how to make it send back true for inherited keys when I
>> > need to fork the lookup based on instances that are `WeakMap`ed to the
>> > `receiver`.
>> ___
>> 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: Re: Proxy handler.has() does not have a receiver argument?

2019-11-22 Thread Cyril Auburtin
It's not answering your issue with Proxy but more about multiple inheritance

It can be solved in a static way:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#Mix-ins

Concrete example here:
https://github.com/pepabo/gmopg/blob/master/src/gmopg.ts#L10

On Fri, Nov 22, 2019 at 4:23 AM #!/JoePea  wrote:

> After messing with Proxy-on-prototypes for two days, I've just come to
> the conclusion that I probably need to have Proxies on this (the
> receiver) returned from constructors to achieve what I want. At least,
> it's much easier to code it that way. I think it'd be nice to have
> receiver on all inheritance-related traps. That might make some things
> easier.
>
> On Thu, Nov 21, 2019 at 2:55 PM #!/JoePea  wrote:
> >
> > I really thing that because `has` is about detecting inherited
> > properties, the `receiver` parameter should be included. For things
> > like `ownKeys`, which are not about inheritance, then yeah, let's not
> > add receiver there.
> >
> > I'm trying to implement my own multiple inheritance, but now I
> > stumbled on how to make it send back true for inherited keys when I
> > need to fork the lookup based on instances that are `WeakMap`ed to the
> > `receiver`.
> ___
> 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: Re: Proxy handler.has() does not have a receiver argument?

2019-11-21 Thread #!/JoePea
After messing with Proxy-on-prototypes for two days, I've just come to
the conclusion that I probably need to have Proxies on this (the
receiver) returned from constructors to achieve what I want. At least,
it's much easier to code it that way. I think it'd be nice to have
receiver on all inheritance-related traps. That might make some things
easier.

On Thu, Nov 21, 2019 at 2:55 PM #!/JoePea  wrote:
>
> I really thing that because `has` is about detecting inherited
> properties, the `receiver` parameter should be included. For things
> like `ownKeys`, which are not about inheritance, then yeah, let's not
> add receiver there.
>
> I'm trying to implement my own multiple inheritance, but now I
> stumbled on how to make it send back true for inherited keys when I
> need to fork the lookup based on instances that are `WeakMap`ed to the
> `receiver`.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Proxy Reflect.has() call causes infinite recursion? (#!/JoePea)

2019-11-21 Thread #!/JoePea
Any idea why it isn't spamming the console? I mean, if it is
recursive, shouldn't it fire my console.logs over and over, like
50,000 times, before finally throwing the error?

On Thu, Nov 21, 2019 at 3:12 PM Alex Vincent  wrote:
>
> I'm afraid your testcase is still far too complicated to really figure out at 
> first glance.  It looks like you're trying to implement a mixin pattern.
>
> In my experience, it's better to implement the getPrototypeOf, 
> getOwnPropertyDescriptor, and defineProperty traps, and maybe make your get, 
> set, and has traps depend on them.
>
> Yes, that means you have to read the ECMAScript specification, section 9.5 
> carefully.  Yes, it's a major pain point.  I can only point you to my own 
> efforts in es-membrane to implement the specified traps.
>
> https://github.com/ajvincent/es-membrane/blob/master/source/ObjectGraphHandler.js
> ___
> 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: Proxy Reflect.has() call causes infinite recursion? (#!/JoePea)

2019-11-21 Thread Alex Vincent
I'm afraid your testcase is still far too complicated to really figure out
at first glance.  It looks like you're trying to implement a mixin pattern.

In my experience, it's better to implement the getPrototypeOf,
getOwnPropertyDescriptor, and defineProperty traps, and maybe make your
get, set, and has traps depend on them.

Yes, that means you have to read the ECMAScript specification, section 9.5
carefully.  Yes, it's a major pain point.  I can only point you to my own
efforts in es-membrane to implement the specified traps.

https://github.com/ajvincent/es-membrane/blob/master/source/ObjectGraphHandler.js
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Re: Proxy handler.has() does not have a receiver argument?

2019-11-21 Thread #!/JoePea
I really thing that because `has` is about detecting inherited
properties, the `receiver` parameter should be included. For things
like `ownKeys`, which are not about inheritance, then yeah, let's not
add receiver there.

I'm trying to implement my own multiple inheritance, but now I
stumbled on how to make it send back true for inherited keys when I
need to fork the lookup based on instances that are `WeakMap`ed to the
`receiver`.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Proxy Reflect.has() call causes infinite recursion?

2019-11-21 Thread #!/JoePea
Sorry you all, I realized I should've simplified it. Here's a [simpler
fiddle](https://jsfiddle.net/trusktr/tf6hdn48/6/).

On Thu, Nov 21, 2019 at 1:17 PM #!/JoePea  wrote:
>
> I was trying to implement "multiple inheritance" in the following code
> ([jsfiddle](https://jsfiddle.net/trusktr/tf6hdn48/)), but it gives a
> max call stack (infinite recursion) error.
>
> However, the infinite recursion does not execute any of my console.log
> statements repeatedly like I'd expect, so it seems that the infinite
> recursion is happening inside the JS engine?
>
> What's going on?
>
> Here's the code for reference, see "PROXY INFINITE RECURSION" comments
> for the site where the problem is happening (as far as I can tell in
> devtools):
>
> ```js
> "use strict";
>
> function multiple(...classes) {
> if (classes.length === 0)
> return Object;
> if (classes.length === 1) {
> const result = classes[0];
> return (typeof result === 'function' ? result : Object);
> }
>
> const FirstClass = classes.shift();
> const __instances__ = new WeakMap();
> const getInstances = (inst) => {
> let result = __instances__.get(inst);
> if (!result)
> __instances__.set(inst, (result = []));
> return result;
> };
>
> class MultiClass extends FirstClass {
> constructor(...args) {
> super(...args);
>
> const protoBeforeMultiClassProto =
> findPrototypeBeforeMultiClassPrototype(this, MultiClass.prototype);
> if (protoBeforeMultiClassProto)
> Object.setPrototypeOf(protoBeforeMultiClassProto,
> newMultiClassPrototype);
>
> const instances = getInstances(this);
>
> for (const Ctor of classes)
> instances.push(new Ctor(...args));
> }
> }
>
> let count = 0;
> const newMultiClassPrototype = new Proxy({
> __proto__: MultiClass.prototype,
> }, {
> get(target, key, self) {
> if (count++ < 500) console.log(' --- get', key);
>
> if (Reflect.has(MultiClass.prototype, key))
> return Reflect.get(MultiClass.prototype, key, self);
>
> for (const instance of getInstances(self))
> if (Reflect.has(instance, key))
> return Reflect.get(instance, key, self);
>
> return undefined;
> },
>
> set(target, key, value, self) {
> console.log(' - set1', key, value);
>
> // PROXY INFINITE RECURSION HERE:
> console.log('h?',
> Reflect.has(MultiClass.prototype, key));
>
> console.log(' - set1.5', key, value);
>
> if (Reflect.has(MultiClass.prototype, key)) {
> return Reflect.set(target, key, value, self);
> }
>
> const instances = getInstances(self);
>
> for (const instance of instances) {
> if (Reflect.has(instance, key)) {
> return Reflect.set(instance, key, value, self);
> }
> }
>
> return Reflect.set(target, key, value, self);
> },
> });
>
> return MultiClass;
> }
>
> function findPrototypeBeforeMultiClassPrototype(obj, multiClassPrototype) {
> let previous = obj;
> let current = Object.getPrototypeOf(obj);
> while (current) {
> // debugger
> if (current === multiClassPrototype)
> return previous;
> previous = current;
> current = Object.getPrototypeOf(current);
> }
> return null;
> }
>
> async function test() {
> await new Promise(r => setTimeout(r, 3000));
> console.log('-');
> const R1 = multiple();
> const r1 = new R1();
> console.log(Object.keys(r1));
> console.log('-');
> class Foo {
> constructor() {
> this.f = false;
> }
> }
> const R2 = multiple(Foo);
> const r2 = new R2();
> console.log(r2.hasOwnProperty);
> console.log('f', r2.f);
> console.log('-');
> class Bar {
> constructor() {
> this.b = 'asf';
> }
> }
> const R3 = multiple(Foo, Bar);
> const r3 = new R3();
> console.log(r3.hasOwnProperty);
> console.log('f', r3.f);
> console.log('b', r3.b);
> console.log('-');
> class Baz {
> constructor() {
> this.z = 1;
> }
> }
> const R4 = multiple(Foo, Bar, Baz);
> const r4 = new R4();
> console.log(r4.hasOwnProperty);
> console.log('f', r4.f);
> console.log('b', r4.b);
> console.log('z', r4.z);
> class One {
> constructor(arg) {
> this.one = 1;
> console.log('One constructor');
> // this.one = arg
> }
> foo() {
> 

Re: Proxy target/handler access leak in Node

2018-09-17 Thread Darien Valentine
> Making is a public symbol in this manner means it is almost impossible to
deny. It is still true that "util" is deniable, so this isn't necessarily
fatal. I am not yet oriented enough to understand what the consequences are
of suppressing util; but I am worried.

I wasn’t under the impression that the util.inspect.custom symbol or the
functionality it provides is itself problematic. It just happens to be
possible to use it, currently, to get inside the proxy target/handler
because its second argument is an object with a property whose value is a
function that can be called with proxy target / handler values, yet that
property may be overwritten by user code. This is very unlikely to have
been an intentional facet of the API, so making `opts.stylize`
unwritable/unconfigurable shouldn’t reduce the usefulness of custom inspect
implementations, and afaict this would block off the avenue by which
references to target/handler can escape util.js.

Is there another reason why the util.inspect.custom symbol contract would
be an issue?

On Mon, Sep 17, 2018 at 1:21 PM Mark Miller  wrote:

> > The Node.js trust model assumes that all code is trusted.
>
> First I want to respond to this sentence out of context. I often hear such
> phrases. I know what people mean by this, but the phrase "trusted" here
> *always* leads to confusion and muddy thinking. I don't trust the code I
> wrote yesterday. Instead, what we mean by this is something like:
>
> "The Node.js  model assumes we are fully vulnerable to all code."
>
> This phrasing helps us notice some of the questions made obscure by the
> earlier phrase. What is fully vulnerable to which code? What is meant in
> this case is presumably something more like
>
> "...assumes the Node.js process is fully vulnerable to all code it is
> asked to run."
>
> Under a traditional OS, a process executes as the account (or "user")
> executing that process, and has all the permissions of that user. So this
> becomes:
>
> "...assumes the user is fully vulnerable to all code that any Node process
> executing as that user is asked to run."
>
> (Which of course includes anything built on Electron, which makes the
> situation even worse in some ways.)
>
> Given the way that this body of code is typically selected, by transitive
> alleged package dependencies, this is a ridiculously large attack surface.
> Fortunately, there is increasing appreciation that such pervasive
> vulnerability is problematic.
>
> See
>
> https://www.youtube.com/watch?v=9Snbss_tawI=PLKr-mvz8uvUgybLg53lgXSeLOp4BiwvB2=23
>
> Also relevant
>
> https://www.youtube.com/watch?v=wQHjITxQX0g=PLKr-mvz8uvUgybLg53lgXSeLOp4BiwvB2=18
>
> https://www.youtube.com/watch?v=9WdbTucMaRo=PLKr-mvz8uvUgybLg53lgXSeLOp4BiwvB2=10
>
> https://www.youtube.com/watch?v=pig-sIS8_Wc=PLKr-mvz8uvUgybLg53lgXSeLOp4BiwvB2=20
>
> --
>   Cheers,
>   --MarkM
>
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Proxy target/handler access leak in Node

2018-09-17 Thread Mark Miller
> The Node.js trust model assumes that all code is trusted.

First I want to respond to this sentence out of context. I often hear such
phrases. I know what people mean by this, but the phrase "trusted" here
*always* leads to confusion and muddy thinking. I don't trust the code I
wrote yesterday. Instead, what we mean by this is something like:

"The Node.js  model assumes we are fully vulnerable to all code."

This phrasing helps us notice some of the questions made obscure by the
earlier phrase. What is fully vulnerable to which code? What is meant in
this case is presumably something more like

"...assumes the Node.js process is fully vulnerable to all code it is asked
to run."

Under a traditional OS, a process executes as the account (or "user")
executing that process, and has all the permissions of that user. So this
becomes:

"...assumes the user is fully vulnerable to all code that any Node process
executing as that user is asked to run."

(Which of course includes anything built on Electron, which makes the
situation even worse in some ways.)

Given the way that this body of code is typically selected, by transitive
alleged package dependencies, this is a ridiculously large attack surface.
Fortunately, there is increasing appreciation that such pervasive
vulnerability is problematic.

See
https://www.youtube.com/watch?v=9Snbss_tawI=PLKr-mvz8uvUgybLg53lgXSeLOp4BiwvB2=23

Also relevant
https://www.youtube.com/watch?v=wQHjITxQX0g=PLKr-mvz8uvUgybLg53lgXSeLOp4BiwvB2=18
https://www.youtube.com/watch?v=9WdbTucMaRo=PLKr-mvz8uvUgybLg53lgXSeLOp4BiwvB2=10
https://www.youtube.com/watch?v=pig-sIS8_Wc=PLKr-mvz8uvUgybLg53lgXSeLOp4BiwvB2=20

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


Re: Proxy target/handler access leak in Node

2018-09-17 Thread Mark Miller
On Mon, Sep 17, 2018 at 8:32 AM Darien Valentine 
wrote:

> Thanks for the context, James. Yes, this thread mainly concerns the issue
> of being able to obtain references to values within the handler/target from
> external code, though I did try to make a case for not having the showProxy
> option in the original issue thread.
>
> I would also not have thought to call it an “attack” vector. Mark would be
> able to say better for sure though. It does make an invariant of the
> language violable though. It’s similar to exposing a function which, given
> only a function object, may return references to arbitrary values from that
> function’s scope.
>

> It’s similar to exposing a function which, given only a function object,
may return references to arbitrary values from that function’s scope.

This is an apt comparison. A debugger has access to such info. Likewise, in
a secure OS, when one process is able to debug another, the first process
can read any data from the address space of the second. There have even
been language implementations that were otherwise supposed to be memory
safe that had "peek" and "poke" operations for reading and writing
arbitrary memory locations from programs in the language. Of course, memory
allocators and garbage collectors typically need such access.

Whether these are "attacks" or "vulnerabilities" depends on how such
permission for debug-level access or peek/poke access is controlled and
provided.

>From a bit of web searching, I found the following worrisome:

https://github.com/nodejs/node/pull/20857
https://github.com/nodejs/node/commit/dadd6e16888baac8fd110432b81f3fd1237be3e1
seemingly in response to
https://github.com/nodejs/node/issues/20821
https://github.com/nodejs/node/issues/22671

Making is a public symbol in this manner means it is almost impossible to
deny. It is still true that "util" is deniable, so this isn't necessarily
fatal. I am not yet oriented enough to understand what the consequences are
of suppressing util; but I am worried.

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


Re: Proxy target/handler access leak in Node

2018-09-17 Thread Darien Valentine
Thanks for the context, James. Yes, this thread mainly concerns the issue
of being able to obtain references to values within the handler/target from
external code, though I did try to make a case for not having the showProxy
option in the original issue thread.

I would also not have thought to call it an “attack” vector. Mark would be
able to say better for sure though. It does make an invariant of the
language violable though. It’s similar to exposing a function which, given
only a function object, may return references to arbitrary values from that
function’s scope.

On Mon, Sep 17, 2018 at 5:45 AM James M Snell  wrote:

> Some background as I am the one who added the showProxy feature into
> Node.js...
>
> util.inspect() is considered by Node.js to be a diagnostics API. The
> intent is to allow adequate debugging in a variety of scenarios. This was
> added to address a user issue where inspection of a Proxy object (that the
> user didn't know was a proxy object) would cause an infinite loop when
> invoking a certain getter that just happened to have a console.log
> statement (in Node.js, console.log uses util.inspect in some cases. There
> are cases where one does need to know when an object is a Proxy.
>
> That said, the specific issue in this thread is a bit different. When
> implementing showProxy, I took the additional step of introspecting the
> component elements of the proxy because the goal of util.inspect is to
> provide as much insight as possible about the object being inspected. The
> ability to provide a custome stylize function for inspect is a long
> standing feature of Node.js long before showProxy was introduced.
>
> One thing I would not classify this as is an attack, exploit, or
> vulnerability. The Node.js trust model assumes that all code is trusted. I
> can, however, bring this issue to the Node.js project and see how folks
> would feel about not exposing the internal objects when a Proxy is
> detected. That would reduce the diagnostic utility of util.inspect with
> Proxy objects, which is unfortunate, but it would resolve the issue here.
> Removing this would likely require a proper deprecation of the existing
> functionality which is a semver-major change.
>
> The final thing I would say is: Node.js has a responsible disclosure
> process for potential security vulnerability reports. If one feels that
> some behavior implemented by node.js presents a vulnerability or attack
> vector, I would encourage them to please use our HackerOne site (
> https://hackerone.com/nodejs) to report the issue before discussing in a
> public forum so that the potential risks can be evaluated before public
> disclosure.
>
>
>
> On Mon, Sep 17, 2018, 02:19 Darien Valentine 
> wrote:
>
>> > What is going on here? Can you explain?
>>
>> A C++/V8 API is used to obtain references to the target and handler from
>> only the proxy object, even though those objects aren’t supposed to be
>> available to this ES scope:
>>
>> https://github.com/nodejs/node/blob/master/lib/util.js#L642-L647
>>
>> The pair of objects is passed to another function, which in turn may pass
>> values to the method "ctx.stylize", but that property may have been
>> previously overwritten from user code:
>>
>> https://github.com/nodejs/node/blob/master/lib/util.js#L566-L580
>>
>> AFAICT, fixing the leak (beyond util.js) would be possible by making
>> `stylize` unconfigurable/unwritable. However there may be other avenues
>> here — I’m not sure.
>>
>> > Does that mean this attack is impossible from code loaded into a new
>> realm as made by the shim or SES?
>>
>> The exploit isn’t sensitive to realm-of-origin, since util is using v8
>> internals to get the references, not e.g. a patched version of Proxy. But
>> it still depends on the proxy object in question being exposed to a context
>> where util.inspect exists.
>>
>> In the [issue comment](
>> https://github.com/nodejs/node/issues/10731#issuecomment-419008987), I
>> wrote this:
>>
>> > This exploit can be fixed pretty easily. But I think it’s symptomatic.
>> My understanding was that V8’s C++ APIs are intended for making external
>> functionality available to ECMAScript using ECMAScript values and
>> ECMAScript semantics. Here though, it is being used to bypass ECMAScript
>> semantics. The behavior seen in the above script isn’t possible in
>> ECMAScript — but neither is distinguishing between objects which have been
>> implemented as ordinary objects and objects implemented as proxy exotic
>> objects.
>>
>>
>> On Sun, Sep 16, 2018 at 8:06 PM Mark Miller  wrote:
>>
>>> This is indeed quite scary. I have never used of explored the Node
>>> `util` API. What is going on here? Can you explain?
>>>
>>> The Realms shim and SES (which build on the Realms shim) create an
>>> environment in which only those globals defined by EcmaScript, not by the
>>> host, are present by default.
>>> https://github.com/Agoric/SES/tree/master/demo
>>> https://rawgit.com/Agoric/SES/master/demo/
>>> Does 

Re: Proxy target/handler access leak in Node

2018-09-17 Thread James M Snell
Some background as I am the one who added the showProxy feature into
Node.js...

util.inspect() is considered by Node.js to be a diagnostics API. The intent
is to allow adequate debugging in a variety of scenarios. This was added to
address a user issue where inspection of a Proxy object (that the user
didn't know was a proxy object) would cause an infinite loop when invoking
a certain getter that just happened to have a console.log statement (in
Node.js, console.log uses util.inspect in some cases. There are cases where
one does need to know when an object is a Proxy.

That said, the specific issue in this thread is a bit different. When
implementing showProxy, I took the additional step of introspecting the
component elements of the proxy because the goal of util.inspect is to
provide as much insight as possible about the object being inspected. The
ability to provide a custome stylize function for inspect is a long
standing feature of Node.js long before showProxy was introduced.

One thing I would not classify this as is an attack, exploit, or
vulnerability. The Node.js trust model assumes that all code is trusted. I
can, however, bring this issue to the Node.js project and see how folks
would feel about not exposing the internal objects when a Proxy is
detected. That would reduce the diagnostic utility of util.inspect with
Proxy objects, which is unfortunate, but it would resolve the issue here.
Removing this would likely require a proper deprecation of the existing
functionality which is a semver-major change.

The final thing I would say is: Node.js has a responsible disclosure
process for potential security vulnerability reports. If one feels that
some behavior implemented by node.js presents a vulnerability or attack
vector, I would encourage them to please use our HackerOne site (
https://hackerone.com/nodejs) to report the issue before discussing in a
public forum so that the potential risks can be evaluated before public
disclosure.



On Mon, Sep 17, 2018, 02:19 Darien Valentine  wrote:

> > What is going on here? Can you explain?
>
> A C++/V8 API is used to obtain references to the target and handler from
> only the proxy object, even though those objects aren’t supposed to be
> available to this ES scope:
>
> https://github.com/nodejs/node/blob/master/lib/util.js#L642-L647
>
> The pair of objects is passed to another function, which in turn may pass
> values to the method "ctx.stylize", but that property may have been
> previously overwritten from user code:
>
> https://github.com/nodejs/node/blob/master/lib/util.js#L566-L580
>
> AFAICT, fixing the leak (beyond util.js) would be possible by making
> `stylize` unconfigurable/unwritable. However there may be other avenues
> here — I’m not sure.
>
> > Does that mean this attack is impossible from code loaded into a new
> realm as made by the shim or SES?
>
> The exploit isn’t sensitive to realm-of-origin, since util is using v8
> internals to get the references, not e.g. a patched version of Proxy. But
> it still depends on the proxy object in question being exposed to a context
> where util.inspect exists.
>
> In the [issue comment](
> https://github.com/nodejs/node/issues/10731#issuecomment-419008987), I
> wrote this:
>
> > This exploit can be fixed pretty easily. But I think it’s symptomatic.
> My understanding was that V8’s C++ APIs are intended for making external
> functionality available to ECMAScript using ECMAScript values and
> ECMAScript semantics. Here though, it is being used to bypass ECMAScript
> semantics. The behavior seen in the above script isn’t possible in
> ECMAScript — but neither is distinguishing between objects which have been
> implemented as ordinary objects and objects implemented as proxy exotic
> objects.
>
>
> On Sun, Sep 16, 2018 at 8:06 PM Mark Miller  wrote:
>
>> This is indeed quite scary. I have never used of explored the Node `util`
>> API. What is going on here? Can you explain?
>>
>> The Realms shim and SES (which build on the Realms shim) create an
>> environment in which only those globals defined by EcmaScript, not by the
>> host, are present by default.
>> https://github.com/Agoric/SES/tree/master/demo
>> https://rawgit.com/Agoric/SES/master/demo/
>> Does that mean this attack is impossible from code loaded into a new
>> realm as made by the shim or SES?
>>
>>
>>
>> On Sun, Sep 16, 2018 at 12:10 PM Mike Samuel 
>> wrote:
>>
>>> Nicely done!
>>>
>>> One more reason to prefer WeakMaps to properties when relating objects
>>> and secrets.
>>>
>>>
>>>
>>> On Sun, Sep 16, 2018 at 2:59 PM Darien Valentine 
>>> wrote:
>>>
 A few weeks ago I’d commented on an open Node github issue regarding
 Proxies and inspection. While the bulk of the comment concerns an opinion
 that proxies should not be treated as special case, I included an example
 of a mechanism by which the current implementation allows outside code to
 access the target and handler objects of a proxy that it does not own.


Re: Proxy target/handler access leak in Node

2018-09-16 Thread Isiah Meadows
In the browser, I could see why not to allow it by default: it's a
potential security hole, and GC concerns do exist (what happens if the
symbol's data is no longer accessible without reflection?).

In embeddings, I'm not sure if there's any real problem, considering
Node's `vm` API allows proper sandboxing to prevent scripts from
getting ahold of a `util` object in the first place, and by extension,
the private data assigned to it.

It might be worth accepting a level of non-determinism within the spec
stating that if a symbol is deemed not accessible by the
implementation, they aren't required to return it. Objects would have
to hold those private symbols weakly, but the non-determinism would
need to clarified with the weak ref proposal. (This is primarily a
concern with private symbols, and an implementation might choose not
to expose that in the first place, even to embedders.)

-

Isiah Meadows
cont...@isiahmeadows.com
www.isiahmeadows.com

On Sun, Sep 16, 2018 at 9:19 PM Darien Valentine  wrote:
>
> > What is going on here? Can you explain?
>
> A C++/V8 API is used to obtain references to the target and handler from only 
> the proxy object, even though those objects aren’t supposed to be available 
> to this ES scope:
>
> https://github.com/nodejs/node/blob/master/lib/util.js#L642-L647
>
> The pair of objects is passed to another function, which in turn may pass 
> values to the method "ctx.stylize", but that property may have been 
> previously overwritten from user code:
>
> https://github.com/nodejs/node/blob/master/lib/util.js#L566-L580
>
> AFAICT, fixing the leak (beyond util.js) would be possible by making 
> `stylize` unconfigurable/unwritable. However there may be other avenues here 
> — I’m not sure.
>
> > Does that mean this attack is impossible from code loaded into a new realm 
> > as made by the shim or SES?
>
> The exploit isn’t sensitive to realm-of-origin, since util is using v8 
> internals to get the references, not e.g. a patched version of Proxy. But it 
> still depends on the proxy object in question being exposed to a context 
> where util.inspect exists.
>
> In the [issue 
> comment](https://github.com/nodejs/node/issues/10731#issuecomment-419008987), 
> I wrote this:
>
> > This exploit can be fixed pretty easily. But I think it’s symptomatic. My 
> > understanding was that V8’s C++ APIs are intended for making external 
> > functionality available to ECMAScript using ECMAScript values and 
> > ECMAScript semantics. Here though, it is being used to bypass ECMAScript 
> > semantics. The behavior seen in the above script isn’t possible in 
> > ECMAScript — but neither is distinguishing between objects which have been 
> > implemented as ordinary objects and objects implemented as proxy exotic 
> > objects.
>
>
> On Sun, Sep 16, 2018 at 8:06 PM Mark Miller  wrote:
>>
>> This is indeed quite scary. I have never used of explored the Node `util` 
>> API. What is going on here? Can you explain?
>>
>> The Realms shim and SES (which build on the Realms shim) create an 
>> environment in which only those globals defined by EcmaScript, not by the 
>> host, are present by default.
>> https://github.com/Agoric/SES/tree/master/demo
>> https://rawgit.com/Agoric/SES/master/demo/
>> Does that mean this attack is impossible from code loaded into a new realm 
>> as made by the shim or SES?
>>
>>
>>
>> On Sun, Sep 16, 2018 at 12:10 PM Mike Samuel  wrote:
>>>
>>> Nicely done!
>>>
>>> One more reason to prefer WeakMaps to properties when relating objects and 
>>> secrets.
>>>
>>>
>>>
>>> On Sun, Sep 16, 2018 at 2:59 PM Darien Valentine  
>>> wrote:

 A few weeks ago I’d commented on an open Node github issue regarding 
 Proxies and inspection. While the bulk of the comment concerns an opinion 
 that proxies should not be treated as special case, I included an example 
 of a mechanism by which the current implementation allows outside code to 
 access the target and handler objects of a proxy that it does not own.

 On reflection I realized this specific issue might be worth drawing more 
 attention to.

 ```js
 const util = require('util');

 const victim = new Proxy({}, {
   SECRET: 'Nothing outside can access this'
 });

 let secret;

 const invariantViolator = {
   [util.inspect.custom](depth, options) {
 const { stylize } = options;

 options.showProxy = true;

 options.stylize = (value, color) => {
   secret = value;
   options.stylize = stylize;
   return stylize(value, color);
 };

 return victim;
   }
 };

 util.inspect(invariantViolator);

 console.log(secret); // 'Nothing outside can access this'
 ```

 The implication is that even if running Node with no C++ addons, it is 
 presently possible for proxies to be violated using just the standard lib, 
 which may be significant from a 

Re: Proxy target/handler access leak in Node

2018-09-16 Thread Darien Valentine
> What is going on here? Can you explain?

A C++/V8 API is used to obtain references to the target and handler from
only the proxy object, even though those objects aren’t supposed to be
available to this ES scope:

https://github.com/nodejs/node/blob/master/lib/util.js#L642-L647

The pair of objects is passed to another function, which in turn may pass
values to the method "ctx.stylize", but that property may have been
previously overwritten from user code:

https://github.com/nodejs/node/blob/master/lib/util.js#L566-L580

AFAICT, fixing the leak (beyond util.js) would be possible by making
`stylize` unconfigurable/unwritable. However there may be other avenues
here — I’m not sure.

> Does that mean this attack is impossible from code loaded into a new
realm as made by the shim or SES?

The exploit isn’t sensitive to realm-of-origin, since util is using v8
internals to get the references, not e.g. a patched version of Proxy. But
it still depends on the proxy object in question being exposed to a context
where util.inspect exists.

In the [issue comment](
https://github.com/nodejs/node/issues/10731#issuecomment-419008987), I
wrote this:

> This exploit can be fixed pretty easily. But I think it’s symptomatic. My
understanding was that V8’s C++ APIs are intended for making external
functionality available to ECMAScript using ECMAScript values and
ECMAScript semantics. Here though, it is being used to bypass ECMAScript
semantics. The behavior seen in the above script isn’t possible in
ECMAScript — but neither is distinguishing between objects which have been
implemented as ordinary objects and objects implemented as proxy exotic
objects.


On Sun, Sep 16, 2018 at 8:06 PM Mark Miller  wrote:

> This is indeed quite scary. I have never used of explored the Node `util`
> API. What is going on here? Can you explain?
>
> The Realms shim and SES (which build on the Realms shim) create an
> environment in which only those globals defined by EcmaScript, not by the
> host, are present by default.
> https://github.com/Agoric/SES/tree/master/demo
> https://rawgit.com/Agoric/SES/master/demo/
> Does that mean this attack is impossible from code loaded into a new realm
> as made by the shim or SES?
>
>
>
> On Sun, Sep 16, 2018 at 12:10 PM Mike Samuel  wrote:
>
>> Nicely done!
>>
>> One more reason to prefer WeakMaps to properties when relating objects
>> and secrets.
>>
>>
>>
>> On Sun, Sep 16, 2018 at 2:59 PM Darien Valentine 
>> wrote:
>>
>>> A few weeks ago I’d commented on an open Node github issue regarding
>>> Proxies and inspection. While the bulk of the comment concerns an opinion
>>> that proxies should not be treated as special case, I included an example
>>> of a mechanism by which the current implementation allows outside code to
>>> access the target and handler objects of a proxy that it does not own.
>>>
>>> On reflection I realized this specific issue might be worth drawing more
>>> attention to.
>>>
>>> ```js
>>> const util = require('util');
>>>
>>> const victim = new Proxy({}, {
>>>   SECRET: 'Nothing outside can access this'
>>> });
>>>
>>> let secret;
>>>
>>> const invariantViolator = {
>>>   [util.inspect.custom](depth, options) {
>>> const { stylize } = options;
>>>
>>> options.showProxy = true;
>>>
>>> options.stylize = (value, color) => {
>>>   secret = value;
>>>   options.stylize = stylize;
>>>   return stylize(value, color);
>>> };
>>>
>>> return victim;
>>>   }
>>> };
>>>
>>> util.inspect(invariantViolator);
>>>
>>> console.log(secret); // 'Nothing outside can access this'
>>> ```
>>>
>>> The implication is that even if running Node with no C++ addons, it is
>>> presently possible for proxies to be violated using just the standard lib,
>>> which may be significant from a security perspective. I’m not sure if
>>> that’s the case in practice, but just in case, I figured I should try to
>>> get eyes on it.
>>>
>>> Note that even if this particular hole is patched, the "analog hole" (so
>>> to speak) of just analyzing the string output remains.
>>> ___
>>> 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
>>
>
>
> --
>   Cheers,
>   --MarkM
>
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Proxy target/handler access leak in Node

2018-09-16 Thread Mark Miller
This is indeed quite scary. I have never used of explored the Node `util`
API. What is going on here? Can you explain?

The Realms shim and SES (which build on the Realms shim) create an
environment in which only those globals defined by EcmaScript, not by the
host, are present by default.
https://github.com/Agoric/SES/tree/master/demo
https://rawgit.com/Agoric/SES/master/demo/
Does that mean this attack is impossible from code loaded into a new realm
as made by the shim or SES?



On Sun, Sep 16, 2018 at 12:10 PM Mike Samuel  wrote:

> Nicely done!
>
> One more reason to prefer WeakMaps to properties when relating objects and
> secrets.
>
>
>
> On Sun, Sep 16, 2018 at 2:59 PM Darien Valentine 
> wrote:
>
>> A few weeks ago I’d commented on an open Node github issue regarding
>> Proxies and inspection. While the bulk of the comment concerns an opinion
>> that proxies should not be treated as special case, I included an example
>> of a mechanism by which the current implementation allows outside code to
>> access the target and handler objects of a proxy that it does not own.
>>
>> On reflection I realized this specific issue might be worth drawing more
>> attention to.
>>
>> ```js
>> const util = require('util');
>>
>> const victim = new Proxy({}, {
>>   SECRET: 'Nothing outside can access this'
>> });
>>
>> let secret;
>>
>> const invariantViolator = {
>>   [util.inspect.custom](depth, options) {
>> const { stylize } = options;
>>
>> options.showProxy = true;
>>
>> options.stylize = (value, color) => {
>>   secret = value;
>>   options.stylize = stylize;
>>   return stylize(value, color);
>> };
>>
>> return victim;
>>   }
>> };
>>
>> util.inspect(invariantViolator);
>>
>> console.log(secret); // 'Nothing outside can access this'
>> ```
>>
>> The implication is that even if running Node with no C++ addons, it is
>> presently possible for proxies to be violated using just the standard lib,
>> which may be significant from a security perspective. I’m not sure if
>> that’s the case in practice, but just in case, I figured I should try to
>> get eyes on it.
>>
>> Note that even if this particular hole is patched, the "analog hole" (so
>> to speak) of just analyzing the string output remains.
>> ___
>> 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
>


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


Re: Proxy target/handler access leak in Node

2018-09-16 Thread Mike Samuel
Nicely done!

One more reason to prefer WeakMaps to properties when relating objects and
secrets.



On Sun, Sep 16, 2018 at 2:59 PM Darien Valentine 
wrote:

> A few weeks ago I’d commented on an open Node github issue regarding
> Proxies and inspection. While the bulk of the comment concerns an opinion
> that proxies should not be treated as special case, I included an example
> of a mechanism by which the current implementation allows outside code to
> access the target and handler objects of a proxy that it does not own.
>
> On reflection I realized this specific issue might be worth drawing more
> attention to.
>
> ```js
> const util = require('util');
>
> const victim = new Proxy({}, {
>   SECRET: 'Nothing outside can access this'
> });
>
> let secret;
>
> const invariantViolator = {
>   [util.inspect.custom](depth, options) {
> const { stylize } = options;
>
> options.showProxy = true;
>
> options.stylize = (value, color) => {
>   secret = value;
>   options.stylize = stylize;
>   return stylize(value, color);
> };
>
> return victim;
>   }
> };
>
> util.inspect(invariantViolator);
>
> console.log(secret); // 'Nothing outside can access this'
> ```
>
> The implication is that even if running Node with no C++ addons, it is
> presently possible for proxies to be violated using just the standard lib,
> which may be significant from a security perspective. I’m not sure if
> that’s the case in practice, but just in case, I figured I should try to
> get eyes on it.
>
> Note that even if this particular hole is patched, the "analog hole" (so
> to speak) of just analyzing the string output remains.
> ___
> 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: Proxy performance: JIT-compilation?

2017-08-08 Thread Allen Wirfs-Brock

> On Aug 8, 2017, at 5:03 PM, Mark Miller  wrote:
> 
> So from y'all's various implementation perspectives, how does 
> https://github.com/tvcutsem/es-lab/issues/21 
>  look? Do you think it would 
> make it easier to achieve much higher performance proxies than we could 
> without these subtle semantic changes? Or do you think we can as easily 
> achieve these performance gains with no observable changes at all?

Detecting mutation of an handler object seems isomorphic to deleting mutation 
of an object on the [[Prototype]] chain of an ordinary object. I suspect a 
smart implementation would use the same detection/invalidation techniques for 
both.  Sure an immutable handler object (or prototype object) may eliminate the 
need for that check, but the mechanism is going to have to be there anyway 
since most prototype objects are mutable.  The basic idea is too lower every 
abstraction to primitive; highly  optimizable  IR. It has to me able to 
optimize potentially mutable dispatch objects (prototypes, etc.) even though 
actual mutation is very rate.  So, not clear if special casing non-mutable 
dispatch objects would be worth added complexity.  Obviously, milage may vary 
among actual designs.

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


Re: Proxy performance: JIT-compilation?

2017-08-08 Thread Mark Miller
So from y'all's various implementation perspectives, how does
https://github.com/tvcutsem/es-lab/issues/21 look? Do you think it would
make it easier to achieve much higher performance proxies than we could
without these subtle semantic changes? Or do you think we can as easily
achieve these performance gains with no observable changes at all?

By "subtle", I mean that it is unlikely to affect any normal code.

(Note that, even if the answer is that they don't help, these changes are
still adequately motivated by the cycle-transparency bug. But it would be
good to know.)




On Tue, Aug 8, 2017 at 3:32 PM, Isiah Meadows 
wrote:

> Yes, it's possible to optimize them using specialized ICs on the proxy
> handler itself, but it would be *far* easier to optimize it if the ICs
> weren't necessary in the first place, since you can just build it into
> the proxy's type, almost like a lazily-generated vtable. It's just far
> less work than the otherwise-necessary complex ICs you'd need
> otherwise.
>
> Even though it is in theory possible to optimize such proxies, it's
> pretty complicated to set up, and JS engines aren't exactly magic.
> -
>
> Isiah Meadows
> m...@isiahmeadows.com
>
> Looking for web consulting? Or a new website?
> Send me an email and we can get started.
> www.isiahmeadows.com
>
>
> On Tue, Aug 8, 2017 at 5:36 PM, Sam Tobin-Hochstadt
>  wrote:
> > On Fri, Aug 4, 2017 at 4:52 PM, Allen Wirfs-Brock 
> wrote:
> >>
> >> On Aug 4, 2017, at 2:22 PM, Mark S. Miller  wrote:
> >>
> >> At https://github.com/tvcutsem/es-lab/issues/21 Tom and I have an idea
> (that
> >> we should turn into a proposal) for a subtle change to proxy semantics
> that
> >> * should break essentially no current code,
> >> * repair the cycle detection transparency violation bug,
> >> * enable many proxies to be *much* faster.
> >>
> >>
> >> I actually don’t see why any semantic changes are needed to enable
> better
> >> Proxy performance. One abstractions are sufficiently lowered, a proxy
> trap
> >> invocation is just a series  of procedure calls (some dynamically
> >> dispatched; some to built-in procedures).  I don’t see any reason why
> the
> >> same sort of PIC+dynamic typed based specialization+inlining that is
> used to
> >> optimize more conventional JS code isn’t also applicable to Proxy using
> >> code.
> >
> > Indeed, this works well in practice with other proxy constructs in
> > other languages -- my collaborators and I have a paper showing this
> > that should be out soon. The only barrier to good proxy performance is
> > implementation work.
> >
> > Sam
> > ___
> > 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
>



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


Re: Proxy performance: JIT-compilation?

2017-08-08 Thread Isiah Meadows
Yes, it's possible to optimize them using specialized ICs on the proxy
handler itself, but it would be *far* easier to optimize it if the ICs
weren't necessary in the first place, since you can just build it into
the proxy's type, almost like a lazily-generated vtable. It's just far
less work than the otherwise-necessary complex ICs you'd need
otherwise.

Even though it is in theory possible to optimize such proxies, it's
pretty complicated to set up, and JS engines aren't exactly magic.
-

Isiah Meadows
m...@isiahmeadows.com

Looking for web consulting? Or a new website?
Send me an email and we can get started.
www.isiahmeadows.com


On Tue, Aug 8, 2017 at 5:36 PM, Sam Tobin-Hochstadt
 wrote:
> On Fri, Aug 4, 2017 at 4:52 PM, Allen Wirfs-Brock  
> wrote:
>>
>> On Aug 4, 2017, at 2:22 PM, Mark S. Miller  wrote:
>>
>> At https://github.com/tvcutsem/es-lab/issues/21 Tom and I have an idea (that
>> we should turn into a proposal) for a subtle change to proxy semantics that
>> * should break essentially no current code,
>> * repair the cycle detection transparency violation bug,
>> * enable many proxies to be *much* faster.
>>
>>
>> I actually don’t see why any semantic changes are needed to enable better
>> Proxy performance. One abstractions are sufficiently lowered, a proxy trap
>> invocation is just a series  of procedure calls (some dynamically
>> dispatched; some to built-in procedures).  I don’t see any reason why the
>> same sort of PIC+dynamic typed based specialization+inlining that is used to
>> optimize more conventional JS code isn’t also applicable to Proxy using
>> code.
>
> Indeed, this works well in practice with other proxy constructs in
> other languages -- my collaborators and I have a paper showing this
> that should be out soon. The only barrier to good proxy performance is
> implementation work.
>
> Sam
> ___
> 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: Proxy performance: JIT-compilation?

2017-08-08 Thread Sam Tobin-Hochstadt
On Fri, Aug 4, 2017 at 4:52 PM, Allen Wirfs-Brock  wrote:
>
> On Aug 4, 2017, at 2:22 PM, Mark S. Miller  wrote:
>
> At https://github.com/tvcutsem/es-lab/issues/21 Tom and I have an idea (that
> we should turn into a proposal) for a subtle change to proxy semantics that
> * should break essentially no current code,
> * repair the cycle detection transparency violation bug,
> * enable many proxies to be *much* faster.
>
>
> I actually don’t see why any semantic changes are needed to enable better
> Proxy performance. One abstractions are sufficiently lowered, a proxy trap
> invocation is just a series  of procedure calls (some dynamically
> dispatched; some to built-in procedures).  I don’t see any reason why the
> same sort of PIC+dynamic typed based specialization+inlining that is used to
> optimize more conventional JS code isn’t also applicable to Proxy using
> code.

Indeed, this works well in practice with other proxy constructs in
other languages -- my collaborators and I have a paper showing this
that should be out soon. The only barrier to good proxy performance is
implementation work.

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


Re: Proxy performance: JIT-compilation?

2017-08-04 Thread kai zhu
of course Proxy is going to cause deoptimization problems when you start 
breaking assumptions about Object builtins (which obviously have more 
aggressive and specialized optimizations than generic methods).  in v8, i 
understand the common-case optimization for builtin getters to be a direct 
property lookup of a c++ hidden class.  adding a trap with dynamic-code to the 
getter throws that direct-lookup out the window and likely no reasonable amount 
jit-optimization will get you back the common-case performance.

> On Aug 5, 2017, at 8:22 AM, Mark Miller  wrote:
> 
> Alex, I'll just point out that you are already engaged in the best kind of 
> activity to get implementors to optimize these paths: Building a membrane 
> library that can get widespread use, which encapsulate the complexity of 
> proxies behind a more usable API, for which these proxy operations are the 
> bottleneck. If these costs were sufficient to deter use of your library this 
> would not be a good strategy. But *many* uses of membranes will be for cases 
> where membrane crossings are rare compared to direct object-to-object 
> interaction on either side of the membrane. For most of these, faster proxies 
> will not matter. But for some of these, proxy performance will not be enough 
> to deter use, but faster proxies would still produce a noticeably more 
> pleasant experience.
> 
> This is a long term strategy. For the short term, if you can manage it, make 
> proxy performance significant in some widely used benchmark suite.
> 
> None of this is meant to detract from the box of chocolate strategy. Try 
> everything!
> 
> 
> 
> On Fri, Aug 4, 2017 at 4:30 PM, Alex Vincent  > wrote:
> So, how many boxes of chocolates do I need to send to the two big vendors in 
> Mountain View?  :-)
> 
> It's been fifteen years since I seriously tried to profile C++ code, and I 
> didn't really know what I was doing back then:  unfamiliar tools, and less 
> competence in C++ than I would've liked.  What little knowledge of profiling 
> I had back then has long since faded.
> 
> Even if I could generate a pretty picture of how long we spent in each code 
> path, I wouldn't know how to interpret it.
> 
> I recently submitted a patch for improving error reporting in SpiderMonkey 
> [1], so I can occasionally dip my toes in the JSAPI code...
> 
> [1] https://bugzilla.mozilla.org/show_bug.cgi?id=1383630 
> 
> 
> On Fri, Aug 4, 2017 at 2:52 PM, Allen Wirfs-Brock  > wrote:
> I don’t think the barriers to such optimization are technical.  It’s more a 
> matter of convincing that engine implementors that doing the work (probably 
> significant)  to optimizing Proxies in this manner is a sound investment and 
> hight priority
> 
> -- 
> "The first step in confirming there is a bug in someone else's work is 
> confirming there are no bugs in your own."
> -- Alexander J. Vincent, June 30, 2001
> 
> ___
> es-discuss mailing list
> es-discuss@mozilla.org 
> https://mail.mozilla.org/listinfo/es-discuss 
> 
> 
> 
> 
> 
> -- 
>   Cheers,
>   --MarkM
> ___
> 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: Proxy performance: JIT-compilation?

2017-08-04 Thread Mark Miller
Alex, I'll just point out that you are already engaged in the best kind of
activity to get implementors to optimize these paths: Building a membrane
library that can get widespread use, which encapsulate the complexity of
proxies behind a more usable API, for which these proxy operations are the
bottleneck. If these costs were sufficient to deter use of your library
this would not be a good strategy. But *many* uses of membranes will be for
cases where membrane crossings are rare compared to direct object-to-object
interaction on either side of the membrane. For most of these, faster
proxies will not matter. But for some of these, proxy performance will not
be enough to deter use, but faster proxies would still produce a noticeably
more pleasant experience.

This is a long term strategy. For the short term, if you can manage it,
make proxy performance significant in some widely used benchmark suite.

None of this is meant to detract from the box of chocolate strategy. Try
everything!



On Fri, Aug 4, 2017 at 4:30 PM, Alex Vincent  wrote:

> So, how many boxes of chocolates do I need to send to the two big vendors
> in Mountain View?  :-)
>
> It's been fifteen years since I seriously tried to profile C++ code, and I
> didn't really know what I was doing back then:  unfamiliar tools, and less
> competence in C++ than I would've liked.  What little knowledge of
> profiling I had back then has long since faded.
>
> Even if I could generate a pretty picture of how long we spent in each
> code path, I wouldn't know how to interpret it.
>
> I recently submitted a patch for improving error reporting in SpiderMonkey
> [1], so I can occasionally dip my toes in the JSAPI code...
>
> [1] https://bugzilla.mozilla.org/show_bug.cgi?id=1383630
>
> On Fri, Aug 4, 2017 at 2:52 PM, Allen Wirfs-Brock 
> wrote:
>
>> I don’t think the barriers to such optimization are technical.  It’s more
>> a matter of convincing that engine implementors that doing the work
>> (probably significant)  to optimizing Proxies in this manner is a sound
>> investment and hight priority
>>
>
> --
> "The first step in confirming there is a bug in someone else's work is
> confirming there are no bugs in your own."
> -- Alexander J. Vincent, June 30, 2001
>
> ___
> es-discuss mailing list
> es-discuss@mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
>


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


Re: Proxy performance: JIT-compilation?

2017-08-04 Thread Alex Vincent
So, how many boxes of chocolates do I need to send to the two big vendors
in Mountain View?  :-)

It's been fifteen years since I seriously tried to profile C++ code, and I
didn't really know what I was doing back then:  unfamiliar tools, and less
competence in C++ than I would've liked.  What little knowledge of
profiling I had back then has long since faded.

Even if I could generate a pretty picture of how long we spent in each code
path, I wouldn't know how to interpret it.

I recently submitted a patch for improving error reporting in SpiderMonkey
[1], so I can occasionally dip my toes in the JSAPI code...

[1] https://bugzilla.mozilla.org/show_bug.cgi?id=1383630

On Fri, Aug 4, 2017 at 2:52 PM, Allen Wirfs-Brock 
wrote:

> I don’t think the barriers to such optimization are technical.  It’s more
> a matter of convincing that engine implementors that doing the work
> (probably significant)  to optimizing Proxies in this manner is a sound
> investment and hight priority
>

-- 
"The first step in confirming there is a bug in someone else's work is
confirming there are no bugs in your own."
-- Alexander J. Vincent, June 30, 2001
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Proxy performance: JIT-compilation?

2017-08-04 Thread Mark S. Miller
On Fri, Aug 4, 2017 at 2:52 PM, Allen Wirfs-Brock 
wrote:

>
> On Aug 4, 2017, at 2:22 PM, Mark S. Miller  wrote:
>
> At https://github.com/tvcutsem/es-lab/issues/21 Tom and I have an idea
> (that we should turn into a proposal) for a subtle change to proxy
> semantics that
> * should break essentially no current code,
> * repair the cycle detection transparency violation bug,
> * enable many proxies to be *much* faster.
>
>
> I actually don’t see why any semantic changes are needed to enable better
> Proxy performance. One abstractions are sufficiently lowered, a proxy trap
> invocation is just a series  of procedure calls (some dynamically
> dispatched; some to built-in procedures).  I don’t see any reason why the
> same sort of PIC+dynamic typed based specialization+inlining that is used
> to optimize more conventional JS code isn’t also applicable to Proxy using
> code.
>
> I don’t think the barriers to such optimization are technical.  It’s more
> a matter of convincing that engine implementors that doing the work
> (probably significant)  to optimizing Proxies in this manner is a sound
> investment and hight priority
>

I agree. So I change the claims to

* should break essentially no current code,
* repair the cycle detection transparency violation bug,
* enable many proxies to be *much* faster with less work by
implementors.

In particular, for many permanently absent traps, the proxy can just pass
these through directly to the target without much analysis.

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


Re: Proxy

2016-12-21 Thread Uther Pendragon
Agreed, but it lacks intent...  I.e., the get handler doesn't know whether
the return value is being called.

Imagine a layer that is so robust and flexible that, to use it, you don't
have to know or care how the things are used...   You just do what makes
sense and it works...  this concept kinda depends on knowing whether
something is being called from, read or assigned when the handler is called.

On Dec 21, 2016 7:05 AM, "Isiah Meadows"  wrote:

> You can always just return a callable from `handler.get`. Function
> closures are much more ergonomic than proxies for that in my experience,
> although I generally make no distinction regarding `this` (which only
> complicates in this area).
>
> On Wed, Dec 14, 2016, 20:47 Uther Pendragon  wrote:
>
>> Perhaps it's a bit late... but I'd like to discuss the proxy object.
>> Notably:  why no way to define a hook for when a property is called as a
>> function.
>>
>> I think I understand *why* there isn't one..  I presume because how a
>> property is used (I.e. as a property or called as a function) is a level
>> deeper than the recalling of said property.  If at all possible, I think it
>> would be incredibly useful.  This may be outside the intended purpose of
>> the proxy object, but a proxy for the purposes of a middleware (I hate that
>> word too) that is more dynamic  would be perfect for adaptors etc...
>> Perhaps it's not feasible, because the proxy hook is best applied at the
>> point when the property's definition, which brings me to my next
>> suggestion
>>
>> What about the ability to alter / define the configuration of a scope
>> variable, like those on objects with defineProperty... but with simple
>> scope variables...  I presume most implementations define scope variables
>> much like object properties internally.
>>
>> On Dec 14, 2016 2:56 PM,  wrote:
>>
>> Send es-discuss mailing list submissions to
>> es-discuss@mozilla.org
>>
>> To subscribe or unsubscribe via the World Wide Web, visit
>> https://mail.mozilla.org/listinfo/es-discuss
>> or, via email, send a message with subject or body 'help' to
>> es-discuss-requ...@mozilla.org
>>
>> You can reach the person managing the list at
>> es-discuss-ow...@mozilla.org
>>
>> When replying, please edit your Subject line so it is more specific
>> than "Re: Contents of es-discuss digest..."
>>
>> Today's Topics:
>>
>>1. Re: Ranges (Jeremy Martin)
>>2. Re: Ranges (Alexander Jones)
>>3. Re: Destructuring object outside of var declaration (Jeff Walden)
>>
>>
>> -- Forwarded message --
>> From: Jeremy Martin 
>> To: Hikaru Nakashima 
>> Cc: es-discuss 
>> Date: Wed, 14 Dec 2016 11:55:02 -0500
>> Subject: Re: Ranges
>> While slightly more verbose, the previously suggested `...` syntax does
>> have a superficial consistency with the spread operator. Both perform an
>> expansion of sorts, which has a subtle elegance to it, IMO.
>>
>> On Wed, Dec 14, 2016 at 4:02 AM, Hikaru Nakashima <
>> oao.hikaru@gmail.com> wrote:
>>
>> I understand.
>> I hope to find a good form of literals.
>>
>> Is there a fact that literals are easier to optimize in the following
>> cases?
>>
>> ```
>> for (let i of [1 to 5]) { .. }
>> vs
>> for (let i of Array.range(1, 5)) { .. }
>> ```
>>
>> If so, it seems that we can attract vendors' interests.
>>
>> 2016-12-14 17:29 GMT+09:00 Andy Earnshaw :
>>
>> I think you'd be lucky to even get to that stage.  Vendors aren't keen on
>> any kind of backwards incompatibility in new specs and trying to get this
>> to stage 4 with such a glaring one would be practically  impossible.
>>
>> It's not just the incompatibility either.  You also introduce an
>> inconsistencies where things like `[1..toFixed(2)]` doesn't mean the same
>> as `[ 1..toFixed(2) ]`. That kind of thing is just confusing to developers.
>>
>> When you consider these things, it becomes clear that it's not practical
>> to change the language this way for such a small benefit.
>>
>> On Wed, 14 Dec 2016, 03:00 Hikaru Nakashima, 
>> wrote:
>>
>> Oh, I understood it.
>> It looks like serious problem, but it is may not actually.
>> If this spec change doesn't break web, we can introduce this idea?
>> ___
>> 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
>>
>>
>>
>>
>> --
>> Jeremy Martin
>> 661.312.3853 <(661)%20312-3853>
>> http://devsmash.com
>> @jmar777
>>
>>
>> -- Forwarded message --
>> From: Alexander Jones 
>> To: Hikaru Nakashima , Jeremy Martin <
>> 

Re: Proxy

2016-12-21 Thread Isiah Meadows
You can always just return a callable from `handler.get`. Function closures
are much more ergonomic than proxies for that in my experience, although I
generally make no distinction regarding `this` (which only complicates in
this area).

On Wed, Dec 14, 2016, 20:47 Uther Pendragon  wrote:

> Perhaps it's a bit late... but I'd like to discuss the proxy object.
> Notably:  why no way to define a hook for when a property is called as a
> function.
>
> I think I understand *why* there isn't one..  I presume because how a
> property is used (I.e. as a property or called as a function) is a level
> deeper than the recalling of said property.  If at all possible, I think it
> would be incredibly useful.  This may be outside the intended purpose of
> the proxy object, but a proxy for the purposes of a middleware (I hate that
> word too) that is more dynamic  would be perfect for adaptors etc...
> Perhaps it's not feasible, because the proxy hook is best applied at the
> point when the property's definition, which brings me to my next
> suggestion
>
> What about the ability to alter / define the configuration of a scope
> variable, like those on objects with defineProperty... but with simple
> scope variables...  I presume most implementations define scope variables
> much like object properties internally.
>
> On Dec 14, 2016 2:56 PM,  wrote:
>
> Send es-discuss mailing list submissions to
> es-discuss@mozilla.org
>
> To subscribe or unsubscribe via the World Wide Web, visit
> https://mail.mozilla.org/listinfo/es-discuss
> or, via email, send a message with subject or body 'help' to
> es-discuss-requ...@mozilla.org
>
> You can reach the person managing the list at
> es-discuss-ow...@mozilla.org
>
> When replying, please edit your Subject line so it is more specific
> than "Re: Contents of es-discuss digest..."
>
> Today's Topics:
>
>1. Re: Ranges (Jeremy Martin)
>2. Re: Ranges (Alexander Jones)
>3. Re: Destructuring object outside of var declaration (Jeff Walden)
>
>
> -- Forwarded message --
> From: Jeremy Martin 
> To: Hikaru Nakashima 
> Cc: es-discuss 
> Date: Wed, 14 Dec 2016 11:55:02 -0500
> Subject: Re: Ranges
> While slightly more verbose, the previously suggested `...` syntax does
> have a superficial consistency with the spread operator. Both perform an
> expansion of sorts, which has a subtle elegance to it, IMO.
>
> On Wed, Dec 14, 2016 at 4:02 AM, Hikaru Nakashima <
> oao.hikaru@gmail.com> wrote:
>
> I understand.
> I hope to find a good form of literals.
>
> Is there a fact that literals are easier to optimize in the following
> cases?
>
> ```
> for (let i of [1 to 5]) { .. }
> vs
> for (let i of Array.range(1, 5)) { .. }
> ```
>
> If so, it seems that we can attract vendors' interests.
>
> 2016-12-14 17:29 GMT+09:00 Andy Earnshaw :
>
> I think you'd be lucky to even get to that stage.  Vendors aren't keen on
> any kind of backwards incompatibility in new specs and trying to get this
> to stage 4 with such a glaring one would be practically  impossible.
>
> It's not just the incompatibility either.  You also introduce an
> inconsistencies where things like `[1..toFixed(2)]` doesn't mean the same
> as `[ 1..toFixed(2) ]`. That kind of thing is just confusing to developers.
>
> When you consider these things, it becomes clear that it's not practical
> to change the language this way for such a small benefit.
>
> On Wed, 14 Dec 2016, 03:00 Hikaru Nakashima, 
> wrote:
>
> Oh, I understood it.
> It looks like serious problem, but it is may not actually.
> If this spec change doesn't break web, we can introduce this idea?
> ___
> 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
>
>
>
>
> --
> Jeremy Martin
> 661.312.3853 <(661)%20312-3853>
> http://devsmash.com
> @jmar777
>
>
> -- Forwarded message --
> From: Alexander Jones 
> To: Hikaru Nakashima , Jeremy Martin <
> jmar...@gmail.com>
> Cc: es-discuss 
> Date: Wed, 14 Dec 2016 20:28:37 +
> Subject: Re: Ranges
> IMO this is quite unnecessary syntax sugar. Python has everything you
> could need here without special syntax.
>
> On Wed, 14 Dec 2016 at 16:55, Jeremy Martin  wrote:
>
> While slightly more verbose, the previously suggested `...` syntax does
> have a superficial consistency with the spread operator. Both perform an
> expansion of sorts, which has a subtle elegance to it, IMO.
>
> On Wed, Dec 14, 2016 at 4:02 AM, Hikaru Nakashima <
> oao.hikaru@gmail.com> 

Re: Proxy

2016-12-14 Thread Andreas Rossberg
On 15 December 2016 at 03:26, Boris Zbarsky  wrote:

> I presume most implementations define scope
>> variables much like object properties internally.
>>
>
> That's not clear to me at all.  In general, non-object environments don't
> need to support all the operations objects do (e.g. you can't delete
> bindings), so the implementation tradeoffs are quite different and using a
> separate codepath for environments and object properties is likely to be
> appropriate.  Certainly the one implementation for which I know this
> details (SpiderMonkey) has quite different implementations for scope
> variables and object properties.


Indeed, the two couldn't be more different. In general, there isn't even a
self-contained data structure representing a scope, let alone a unique one.
Some variables might live in registers, some on the stack, some on the
heap, some in several of those places at different points in time, some are
optimised away entirely. Their names are not generally kept around either.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Proxy

2016-12-14 Thread Boris Zbarsky

On 12/14/16 8:47 PM, Uther Pendragon wrote:

Perhaps it's a bit late... but I'd like to discuss the proxy object.
Notably:  why no way to define a hook for when a property is called as a
function.


See thread at .


I think I understand *why* there isn't one..  I presume because how a
property is used (I.e. as a property or called as a function) is a level
deeper than the recalling of said property.  If at all possible, I think
it would be incredibly useful.


It's possible, in general; it was there in the proxy proposals at some 
point, as the thread linked above says.  It leads to weird consequences 
like "foo.bar()" behaving differently from "foo.bar.call(foo)" when 
everyone expects them to be the same thing.



I presume most implementations define scope
variables much like object properties internally.


That's not clear to me at all.  In general, non-object environments 
don't need to support all the operations objects do (e.g. you can't 
delete bindings), so the implementation tradeoffs are quite different 
and using a separate codepath for environments and object properties is 
likely to be appropriate.  Certainly the one implementation for which I 
know this details (SpiderMonkey) has quite different implementations for 
scope variables and object properties.


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


Re: Proxy handler.has() does not have a receiver argument?

2016-04-03 Thread Michael Theriot
That is good news then. I think I have the right expectations of proxies
now.

Sharing one handler is easy too. All you need to do is map both the `proxy`
and its `target` to the same data. `receiver` is actually the proxy but the
argument is no longer important here.

```js
var priv = new WeakMap();

var handler = {
  get: (target, property, receiver) => property in priv.get(target) ?
priv.get(target)[property] : target[property],
  set: (target, property, value, receiver) => property in
priv.get(target) ? priv.get(target)[property] = value : target[property] =
value,
  has: (target, property) => property in priv.get(target) || property in
target
};

function A() {
  let proxy = new Proxy(this, handler);
  let store = {secret: 4};
  priv.set(this, store).set(proxy, store);
  return proxy;
}

A.prototype.getSecret = function () {
  return priv.get(this).secret;
};

var a = new A();
a.getSecret(); // 4
a.secret; // 4
a.secret = 5;
a.secret; // 5
a.getSecret(); // 5
'secret' in a; // true
```

(sorry for any dupes, new to mailing lists...)

On Thu, Mar 17, 2016 at 5:46 AM, Michael Theriot <
michael.lee.ther...@gmail.com> wrote:

> I feel like it should, or I am misunderstanding something fundamental. I
> made a basic scenario to explain:
>
> ```js
> var arrays = new WeakMap();
>
> function ArrayView(array) {
>   arrays.set(this, array);
>
>   return new Proxy(this, {
> set: (target, property, value) => (arrays.has(this) && property in
> arrays.get(this))  ? arrays.get(this)[property] = value : target[property]
> = value,
> get: (target, property)=> (arrays.has(this) && property in
> arrays.get(this))  ? arrays.get(this)[property] : target[property],
> has: (target, property)=> (arrays.has(this) && property in
> arrays.get(this)) || property in target
>   });
> }
>
> ArrayView.prototype = Object.create(Array.prototype, {
>   arrayLength: {
> get() {
>   return arrays.get(this).length;
> }
>   }
> });
> ```
>
> When `new ArrayView(somearray)` is called the reference to `somearray` is
> stored in the `arrays` weak map and a proxy is returned that allows you to
> manipulate indices on it, or fallback to the object for other properties.
>
> This could be simplified by putting the proxy on the prototype chain to
> reduce overhead and actually return a genuine `ArrayView` object instead:
>
> ```js
> var arrays = new WeakMap();
>
> function ArrayView2(array) {
>   arrays.set(this, array);
> }
>
> var protoLayer = Object.create(Array.prototype, {
>   arrayLength: {
> get() {
>   return arrays.get(this).length;
> }
>   }
> });
>
> ArrayView2.prototype = new Proxy(protoLayer, {
>   set: (target, property, value, receiver) => (arrays.has(receiver) &&
> property in arrays.get(receiver))  ? arrays.get(receiver)[property] = value
> : Reflect.set(target, property, value, receiver),
>   get: (target, property, receiver)=> (arrays.has(receiver) &&
> property in arrays.get(receiver))  ? arrays.get(receiver)[property]
> : Reflect.get(target, property, receiver),
>   has: (target, property)  => (arrays.has(target)   &&
> property in arrays.get(target))   || Reflect.has(target, property)
> });
> ```
>
> Under this setup `target` refers to the protoLayer object which is useless
> here, but we can use the `receiver` argument in its place to access the
> weak map, and replace our set/get operations with Reflect.set/Reflect.get
> calls to the target (protoLayer) using a receiver (the instance) to pass
> the correct `this` value to the `arrayLength` getter and prevent infinite
> recursion.
>
> One problem - handler.has() lacks a receiver argument. So in this scenario
> when using the `in` operator it will always fail on array properties
> because we cannot check the weak map by passing in the instance.
>
> ```js
> var arr = [0, 1];
>
> var a = new ArrayView(arr);
> a.arrayLength; // 2
> 'arrayLength' in a; // true
> '0' in a; // true
> '1' in a; // true
> '2' in a; // false
>
> var b = new ArrayView2(arr);
> b.arrayLength; // 2
> 'arrayLength' in b; // true
> '0' in b; // false
> '1' in b; // false
> '2' in b; // false
> ```
>
> Without a receiver argument on handler.has(), it is practically useless
> for proxies used as a prototype. You can't reference the instance calling
> it and your target is simply the parent prototype.
>
> Is there a reason the handler.has() trap should not obtain the receiver
> when used on the prototype chain? I can understand why Reflect.has()
> wouldn't have a receiver argument (that wouldn't make sense) but this seems
> like a legitimate use for it. Otherwise I don't see a reason to use the
> handler.has() trap at all on prototype proxies except for bizarre behaviors
> that have nothing to do with the instance. It will always have the same
> behavior across all instances since you can't differentiate them.
>
___
es-discuss mailing list
es-discuss@mozilla.org

Re: Proxy handler.has() does not have a receiver argument?

2016-03-20 Thread Allen Wirfs-Brock

> On Mar 18, 2016, at 9:24 AM, Andrea Giammarchi  
> wrote:
> 
> Agreed with everybody else the `receiver` is always needed and `Proxy` on the 
> prototype makes way more sense than per instance.

I don’t agree.  While you certainly can imagine a language where each object’s 
“prototype” determines that object’s fundamental behaviors and provides the MOP 
intercession hooks(in fact that’s how most class-based languages work).  But 
that’s not the JS object model.  Each JS object is essentially a singleton that 
defines it’s own fundamental behaviors.  Whether or this model is better or 
worse than the class-based model isn't really relevant, but in the context of 
JS there are advantage to consistently adhering to that model,

For example, in Michael’s  desired approach, the instance objects of his 
ArrayView abstraction are “ordinary objects”.  One of the fundamental 
behavioral characteristics of ordinary objects is that all of there own 
properties are defined and available to the implementation in a standard way. 
Implementations certainly make use of that characteristic for optimization 
purposes. Michael’s approach would make such optimizations invalid because 
every time an own property needed to be access a prototype walk would have to 
be performed  because there might be an exotic object somewhere on the 
prototype chain that was injecting own property into the original “receiver”.

Michael’s preferred approach also introduces observable irregularity into the 
standard JS inheritance model for ordinary objects.

Consider an object created using Michael’s preferred approach:

```js
var arr = [0, 1];
console.log(Reflect.has(arr,”0”));  //true, arr has “0” as an own property
var subArr = Object.create(arr);
console.log(Reflect.has(subArr,”0”));  //true, all unshadowed properties of 
proto visible from ordinary objects

var b = new ArrayView2(arr);
console.log(Reflect.has(b,”0”));  //true, prototype proxy makes array elements 
visible as if properties of b
var subB= Object.create(b);
console.log(Reflect.has(subB,”0”));  //false, some unshadowed properties of 
proto is not visible from subB
```

Note the his original Proxy implementation does not have this undesirable 
characteristic. 

So what about the use of `receiver` in [[Get]]/[[Set]].  That’s a different 
situation.  [[Get]]/[[Set]] are not fundamental, rather they are derived (they 
work by applying other more fundamental MOP operations). The `receiver` 
argument is not used by them to perform property lookup (they use 
[[GetOwnProperty]] and [[GetPrototypeOf]]) for the actual property lookup).  
`receiver` is only used in the semantics of what happens after the property 
lookup occurs.  Adding a `receiver` argument to the other MOP operations for 
the purpose of changing property lookup semantics seems like a step too far. 
The ES MOP design is a balancing act between capability, implementability, and 
consistency. I think adding `receiver` to every MOP operation would throw the 
design out of balance.

Finally,

Note that we are not really talking about a new capability here.  Michael’s 
first design shows that ES proxies already have the capability to implement the 
object level semantics he desires. So, we are only talking about exactly how he 
goes about using Proxy to implement that semantics. He would prefer a different 
Proxy design than what was actually provided by ES6. But that isn’t what was 
specified or what has now been implemented. We can all imagine how many JS 
features might be “better” if they worked somewhat differently. But that 
generally isn’t an option. The existing language features and their 
implementations are what they are and as JS programmers we need to work within 
that reality.

Allen




















> 
> Also the `getPrototypeOf` trap is really pointless right now
> 
> ```js
> function Yak() {}
> Yak.prototype = new Proxy(Yak.prototype, {
>   getPrototypeOf: (target) => console.log('lulz')
> });
> 
> var yup = new Yak;
> Object.getPrototypeOf(yup);
> ```
> 
> The `target` is actually the original `Yak.prototype` which is already the 
> `yup` prototype: useless trap if used in such way.
> 
> Being also unable to distinguish between `getOwnPropertyNames` vs `keys` is a 
> bit weird.
> 
> `Proxy` looks so close to be that powerful but these bits make it kinda 
> useless for most real-world cases I've been recently dealing with.
> 
> Thanks for any sort of improvement.
> 
> Regards
> 
> 
> 
> 
> On Fri, Mar 18, 2016 at 1:54 PM, Michael Theriot 
> > wrote:
> I'm trying to make the proxy-as-a-prototype pattern work but I've just 
> discovered the `ownKeys` trap is never called on traps on the prototype. So 
> even if the `has` trap is allowed to see the `receiver`, and thus verify the 
> properties "0", "1" exist, this pattern would fail to return the properties 
> "0", "1" exist on an 

Re: Proxy handler.has() does not have a receiver argument?

2016-03-19 Thread Michael Theriot
I'm trying to make the proxy-as-a-prototype pattern work but I've just
discovered the `ownKeys` trap is never called on traps on the prototype. So
even if the `has` trap is allowed to see the `receiver`, and thus verify
the properties "0", "1" exist, this pattern would fail to return the
properties "0", "1" exist on an `Object.getOwnPropertyNames` call.
Disappointing! I'd rather use a proxy on the prototype than create one for
each instance but without a correct `ownKeys` return it just doesn't come
full circle. Is there a trick to make this work or am I out of luck here? I
can only think of actually defining the properties to make it work, which
defeats the idea of using a proxy on the prototype to begin with.

Regardless I agree that traps called on a prototype chain should always
receive the `receiver` as an argument. I think the only trap other than
`set`, `get`, and `has` that can do this is the `getPrototypeOf` trap
(currently does not have a `receiver`) when the `instanceof` check needs to
climb the prototype chain.

On Thu, Mar 17, 2016 at 6:29 PM, Tom Van Cutsem  wrote:

> The rationale for not having a `receiver` argument to `has` is that the
> value produced by the "in" operator is not normally dependent on the
> receiver. This is in contrast with `get` and `set` which may find an
> accessor up the proto chain that needs to run with a `this` bound to the
> receiver.
>
> That said, I follow your line of reasoning and it is true that `has`,
> `get` and `set` are the three traps that can be called on a
> proxy-used-as-prototype (now that `enumerate` is considered deprecated), so
> it would be consistent to allow all of them to  refer back to the original
> receiver. This enables the general pattern that you illustrate.
>
> As you note, the weirdness of this is apparent because it doesn't normally
> make sense to pass a `receiver` argument to Reflect.has(). However, if
> `receiver` would be made visible in a Proxy handler's `has` trap, then
> `Reflect.has` should nevertheless be likewise extended so that one can
> faithfully forward the `receiver` argument.
>
> Spec-wise, I think the only significant change is that 7.3.10 HasProperty
> , step 3
> must be changed to `O.[[HasProperty]](P, O)` and all [[HasProperty]]
> internal methods must likewise be extended with an extra argument (which
> they ignore). Only the Proxy implementation in 9.5.7 would then actually
> refer to that argument.
>
> Cheers,
> Tom
>
> 2016-03-17 11:46 GMT+01:00 Michael Theriot 
> :
>
>> I feel like it should, or I am misunderstanding something fundamental. I
>> made a basic scenario to explain:
>>
>> ```js
>> var arrays = new WeakMap();
>>
>> function ArrayView(array) {
>>   arrays.set(this, array);
>>
>>   return new Proxy(this, {
>> set: (target, property, value) => (arrays.has(this) && property in
>> arrays.get(this))  ? arrays.get(this)[property] = value : target[property]
>> = value,
>> get: (target, property)=> (arrays.has(this) && property in
>> arrays.get(this))  ? arrays.get(this)[property] : target[property],
>> has: (target, property)=> (arrays.has(this) && property in
>> arrays.get(this)) || property in target
>>   });
>> }
>>
>> ArrayView.prototype = Object.create(Array.prototype, {
>>   arrayLength: {
>> get() {
>>   return arrays.get(this).length;
>> }
>>   }
>> });
>> ```
>>
>> When `new ArrayView(somearray)` is called the reference to `somearray` is
>> stored in the `arrays` weak map and a proxy is returned that allows you to
>> manipulate indices on it, or fallback to the object for other properties.
>>
>> This could be simplified by putting the proxy on the prototype chain to
>> reduce overhead and actually return a genuine `ArrayView` object instead:
>>
>> ```js
>> var arrays = new WeakMap();
>>
>> function ArrayView2(array) {
>>   arrays.set(this, array);
>> }
>>
>> var protoLayer = Object.create(Array.prototype, {
>>   arrayLength: {
>> get() {
>>   return arrays.get(this).length;
>> }
>>   }
>> });
>>
>> ArrayView2.prototype = new Proxy(protoLayer, {
>>   set: (target, property, value, receiver) => (arrays.has(receiver) &&
>> property in arrays.get(receiver))  ? arrays.get(receiver)[property] = value
>> : Reflect.set(target, property, value, receiver),
>>   get: (target, property, receiver)=> (arrays.has(receiver) &&
>> property in arrays.get(receiver))  ? arrays.get(receiver)[property]
>> : Reflect.get(target, property, receiver),
>>   has: (target, property)  => (arrays.has(target)   &&
>> property in arrays.get(target))   || Reflect.has(target, property)
>> });
>> ```
>>
>> Under this setup `target` refers to the protoLayer object which is
>> useless here, but we can use the `receiver` argument in its place to access
>> the weak map, and replace our set/get operations with
>> Reflect.set/Reflect.get 

Re: Proxy handler.has() does not have a receiver argument?

2016-03-19 Thread Andrea Giammarchi
AFAIK the reason there is a `receiver` is to deal with prototype cases ...
if that was a good enough reason to have one, every prototype case should
be considered for consistency sake.

We've been advocating prototypal inheritance for 20 years and now it's an
obstacle or "not how JS is"?

```js
class Magic extends new Proxy(unbe, lievable) {
  // please make it happen
  // as it is now, that won't work at all
}
```

Best Regards


On Fri, Mar 18, 2016 at 7:30 PM, Mark S. Miller  wrote:

> I agree with Allen. I am certainly willing -- often eager -- to revisit
> and revise old design decisions that are considered done, when I think the
> cost of leaving it alone exceeds the cost of changing it. In this case, the
> arguments that this extra parameter would be an improvement seem weak. Even
> without the revising-old-decision costs, I am uncertain which decision I
> would prefer. Given these costs, it seems clear we should leave this one
> alone.
>
> Unless it turns out that the cost of leaving it alone is much greater than
> I have understood. If so, please help me see what I'm missing.
>
>
>
>
>
>
> On Fri, Mar 18, 2016 at 12:17 PM, Allen Wirfs-Brock  > wrote:
>
>>
>> On Mar 18, 2016, at 9:24 AM, Andrea Giammarchi <
>> andrea.giammar...@gmail.com> wrote:
>>
>> Agreed with everybody else the `receiver` is always needed and `Proxy` on
>> the prototype makes way more sense than per instance.
>>
>>
>> I don’t agree.  While you certainly can imagine a language where each
>> object’s “prototype” determines that object’s fundamental behaviors and
>> provides the MOP intercession hooks(in fact that’s how most class-based
>> languages work).  But that’s not the JS object model.  Each JS object is
>> essentially a singleton that defines it’s own fundamental behaviors.
>> Whether or this model is better or worse than the class-based model isn't
>> really relevant, but in the context of JS there are advantage to
>> consistently adhering to that model,
>>
>> For example, in Michael’s  desired approach, the instance objects of his
>> ArrayView abstraction are “ordinary objects”.  One of the fundamental
>> behavioral characteristics of ordinary objects is that all of there own
>> properties are defined and available to the implementation in a standard
>> way. Implementations certainly make use of that characteristic for
>> optimization purposes. Michael’s approach would make such optimizations
>> invalid because every time an own property needed to be access a prototype
>> walk would have to be performed  because there might be an exotic object
>> somewhere on the prototype chain that was injecting own property into the
>> original “receiver”.
>>
>> Michael’s preferred approach also introduces observable irregularity into
>> the standard JS inheritance model for ordinary objects.
>>
>> Consider an object created using Michael’s preferred approach:
>>
>> ```js
>> var arr = [0, 1];
>> console.log(Reflect.has(arr,”0”));  //true, arr has “0” as an own property
>> var subArr = Object.create(arr);
>> console.log(Reflect.has(subArr,”0”));  //true, all unshadowed properties
>> of proto visible from ordinary objects
>>
>> var b = new ArrayView2(arr);
>> console.log(Reflect.has(b,”0”));  //true, prototype proxy makes array
>> elements visible as if properties of b
>> var subB= Object.create(b);
>> console.log(Reflect.has(subB,”0”));  //false, some unshadowed properties
>> of proto is not visible from subB
>> ```
>>
>> Note the his original Proxy implementation does not have this undesirable
>> characteristic.
>>
>> So what about the use of `receiver` in [[Get]]/[[Set]].  That’s a
>> different situation.  [[Get]]/[[Set]] are not fundamental, rather they are
>> derived (they work by applying other more fundamental MOP operations). The
>> `receiver` argument is not used by them to perform property lookup (they
>> use [[GetOwnProperty]] and [[GetPrototypeOf]]) for the actual property
>> lookup).  `receiver` is only used in the semantics of what happens after
>> the property lookup occurs.  Adding a `receiver` argument to the other MOP
>> operations for the purpose of changing property lookup semantics seems like
>> a step too far. The ES MOP design is a balancing act between capability,
>> implementability, and consistency. I think adding `receiver` to every MOP
>> operation would throw the design out of balance.
>>
>> Finally,
>>
>> Note that we are not really talking about a new capability here.
>> Michael’s first design shows that ES proxies already have the capability to
>> implement the object level semantics he desires. So, we are only talking
>> about exactly how he goes about using Proxy to implement that semantics. He
>> would prefer a different Proxy design than what was actually provided by
>> ES6. But that isn’t what was specified or what has now been implemented. We
>> can all imagine how many JS features might be “better” if they worked
>> somewhat differently. But that 

Re: Proxy handler.has() does not have a receiver argument?

2016-03-19 Thread Mark S. Miller
I agree with Allen. I am certainly willing -- often eager -- to revisit and
revise old design decisions that are considered done, when I think the cost
of leaving it alone exceeds the cost of changing it. In this case, the
arguments that this extra parameter would be an improvement seem weak. Even
without the revising-old-decision costs, I am uncertain which decision I
would prefer. Given these costs, it seems clear we should leave this one
alone.

Unless it turns out that the cost of leaving it alone is much greater than
I have understood. If so, please help me see what I'm missing.






On Fri, Mar 18, 2016 at 12:17 PM, Allen Wirfs-Brock 
wrote:

>
> On Mar 18, 2016, at 9:24 AM, Andrea Giammarchi <
> andrea.giammar...@gmail.com> wrote:
>
> Agreed with everybody else the `receiver` is always needed and `Proxy` on
> the prototype makes way more sense than per instance.
>
>
> I don’t agree.  While you certainly can imagine a language where each
> object’s “prototype” determines that object’s fundamental behaviors and
> provides the MOP intercession hooks(in fact that’s how most class-based
> languages work).  But that’s not the JS object model.  Each JS object is
> essentially a singleton that defines it’s own fundamental behaviors.
> Whether or this model is better or worse than the class-based model isn't
> really relevant, but in the context of JS there are advantage to
> consistently adhering to that model,
>
> For example, in Michael’s  desired approach, the instance objects of his
> ArrayView abstraction are “ordinary objects”.  One of the fundamental
> behavioral characteristics of ordinary objects is that all of there own
> properties are defined and available to the implementation in a standard
> way. Implementations certainly make use of that characteristic for
> optimization purposes. Michael’s approach would make such optimizations
> invalid because every time an own property needed to be access a prototype
> walk would have to be performed  because there might be an exotic object
> somewhere on the prototype chain that was injecting own property into the
> original “receiver”.
>
> Michael’s preferred approach also introduces observable irregularity into
> the standard JS inheritance model for ordinary objects.
>
> Consider an object created using Michael’s preferred approach:
>
> ```js
> var arr = [0, 1];
> console.log(Reflect.has(arr,”0”));  //true, arr has “0” as an own property
> var subArr = Object.create(arr);
> console.log(Reflect.has(subArr,”0”));  //true, all unshadowed properties
> of proto visible from ordinary objects
>
> var b = new ArrayView2(arr);
> console.log(Reflect.has(b,”0”));  //true, prototype proxy makes array
> elements visible as if properties of b
> var subB= Object.create(b);
> console.log(Reflect.has(subB,”0”));  //false, some unshadowed properties
> of proto is not visible from subB
> ```
>
> Note the his original Proxy implementation does not have this undesirable
> characteristic.
>
> So what about the use of `receiver` in [[Get]]/[[Set]].  That’s a
> different situation.  [[Get]]/[[Set]] are not fundamental, rather they are
> derived (they work by applying other more fundamental MOP operations). The
> `receiver` argument is not used by them to perform property lookup (they
> use [[GetOwnProperty]] and [[GetPrototypeOf]]) for the actual property
> lookup).  `receiver` is only used in the semantics of what happens after
> the property lookup occurs.  Adding a `receiver` argument to the other MOP
> operations for the purpose of changing property lookup semantics seems like
> a step too far. The ES MOP design is a balancing act between capability,
> implementability, and consistency. I think adding `receiver` to every MOP
> operation would throw the design out of balance.
>
> Finally,
>
> Note that we are not really talking about a new capability here.
> Michael’s first design shows that ES proxies already have the capability to
> implement the object level semantics he desires. So, we are only talking
> about exactly how he goes about using Proxy to implement that semantics. He
> would prefer a different Proxy design than what was actually provided by
> ES6. But that isn’t what was specified or what has now been implemented. We
> can all imagine how many JS features might be “better” if they worked
> somewhat differently. But that generally isn’t an option. The existing
> language features and their implementations are what they are and as JS
> programmers we need to work within that reality.
>
> Allen
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
> Also the `getPrototypeOf` trap is really pointless right now
>
> ```js
> function Yak() {}
> Yak.prototype = new Proxy(Yak.prototype, {
>   getPrototypeOf: (target) => console.log('lulz')
> });
>
> var yup = new Yak;
> Object.getPrototypeOf(yup);
> ```
>
> The `target` is actually the original `Yak.prototype` which is already the
> `yup` prototype: useless trap if used in such way.
>
> Being also 

Re: Proxy handler.has() does not have a receiver argument?

2016-03-19 Thread Tom Van Cutsem
2016-03-19 0:15 GMT+01:00 Michael Theriot :

> To be clear, I'm not suggesting behavior like `getOwnPropertyNames` be
> overridden by anything on the prototype, just a way to use proxies without
> having to instantiate identical copies that all use the same handler.
>

If you can already reuse the same handler object between multiple proxies,
you're in good shape. There should be very little overhead in creating many
proxy objects that share the same handler. A proxy object is just an empty
object with a hidden reference to its handler.

Besides, if you want to reliably proxy multiple objects, you must
instantiate a proxy per object anyway, otherwise you may get in trouble
with object-identity. A single proxy object that proxies many different
target objects would have only 1 object identity, so all the proxied
targets would appear to be identity-equal.

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


Re: Proxy handler.has() does not have a receiver argument?

2016-03-19 Thread Michael Theriot
>
> Michael’s preferred approach also introduces observable irregularity into
> the standard JS inheritance model for ordinary objects.
> Consider an object created using Michael’s preferred approach:
> ```js
> var arr = [0, 1];
> console.log(Reflect.has(arr,”0”));  //true, arr has “0” as an own property
> var subArr = Object.create(arr);
> console.log(Reflect.has(subArr,”0”));  //true, all unshadowed properties
> of proto visible from ordinary objects
> var b = new ArrayView2(arr);
> console.log(Reflect.has(b,”0”));  //true, prototype proxy makes array
> elements visible as if properties of b
> var subB= Object.create(b);
> console.log(Reflect.has(subB,”0”));  //false, some unshadowed properties
> of proto is not visible from subB
> ```


I think this relates to the original concern; if you could pass the
receiver this could be resolved. That still leaves `getOwnPropertyNames`
reporting wrong values though and I see no foreseeable way to resolve that
without returning an actual proxy itself.

The reason I'm trying this approach is because I read on the MDN that when
used in the prototype a `receiver` argument is passed that references the
instance, so I assumed this was the intent behind it. The only other
explanation I could think of is that proxies have a receiver to mimic the
`Reflect.set`/`Reflect.get` methods which need a receiver for
getters/setters to work properly, not so you can use them on the prototype
chain.

The other case I would make is every instance would have an identical
proxy, and it just makes sense to put that on the prototype for the same
reasons you put shared methods/properties there.

Note that we are not really talking about a new capability here. Michael’s
> first design shows that ES proxies already have the capability to implement
> the object level semantics he desires.


To be fair I had several obstacles with inheritance using the first version.

```js
var wm1 = new WeakMap();

function A() {
  wm1.set(this, {});
  return new Proxy(this, {});
}

var wm2 = new WeakMap();

function B() {
  A.call(this);
  wm2.set(this, {});
  return new Proxy(this, {});
}

var a = new A();
var b = new B();

wm1.has(a); // true
wm2.has(a); // false

wm1.has(b); // false
wm2.has(b); // true
```

As you can see storing a reference to `this` can't work anymore, since we
actually return a proxy. You can try to work around this...

```js
var wm1 = new WeakMap();

function A() {
  let self = this;
  if(new.target === A) {
self = new Proxy(this, {});
  }
  wm1.set(self, {});
  return self;
}

var wm2 = new WeakMap();

function B() {
  let self = this;
  if(new.target === B) {
self = new Proxy(this, {});
  }
  A.call(self);
  wm2.set(self, {});
  return self;
}

var a = new A();
var b = new B();

wm1.has(a); // true
wm2.has(a); // false

wm1.has(b); // true
wm2.has(b); // true
```

But then problems arise because the new proxy doesn't go through the old
proxy. So anything guaranteed by A()'s proxy is not guaranteed by B()'s
proxy.

```js
var wm1 = new WeakMap();

function A() {
  let self = this;
  if(new.target === A) {
self = new Proxy(this, {
  get: (target, property, receiver) => property === 'bacon' ||
target[property]
});
  }
  wm1.set(self, {});
  return self;
}

var wm2 = new WeakMap();

function B() {
  let self = this;
  if(new.target === B) {
self = new Proxy(this, {
  get: (target, property, receiver) => property === 'ham' ||
target[property]
});
  }
  A.call(self);
  wm2.set(self, {});
  return self;
}

var a = new A();
var b = new B();

wm1.has(a); // true
wm2.has(a); // false

wm1.has(b); // true
wm2.has(b); // true

a.bacon; // true
a.ham; // undefined

b.bacon; // undefined
b.ham; // true
```

(I'm open to solutions on this particular case... One that doesn't require
me to leak the handler of the A proxy)

Ultimately I can actually achieve both what I want with the ArrayView
example and inheritance by using a **lot** of `defineProperty` calls on
`this` in the constructor, but performance is a disaster as you might
expect.

On Fri, Mar 18, 2016 at 2:55 PM, Andrea Giammarchi <
andrea.giammar...@gmail.com> wrote:

> AFAIK the reason there is a `receiver` is to deal with prototype cases ...
> if that was a good enough reason to have one, every prototype case should
> be considered for consistency sake.
>
> We've been advocating prototypal inheritance for 20 years and now it's an
> obstacle or "not how JS is"?
>
> ```js
> class Magic extends new Proxy(unbe, lievable) {
>   // please make it happen
>   // as it is now, that won't work at all
> }
> ```
>
> Best Regards
>
>
> On Fri, Mar 18, 2016 at 7:30 PM, Mark S. Miller 
> wrote:
>
>> I agree with Allen. I am certainly willing -- often eager -- to revisit
>> and revise old design decisions that are considered done, when I think the
>> cost of leaving it alone exceeds the cost of changing it. In this case, the
>> arguments that this extra parameter would be an improvement seem weak. Even

Re: Proxy handler.has() does not have a receiver argument?

2016-03-19 Thread Andrea Giammarchi
Agreed with everybody else the `receiver` is always needed and `Proxy` on
the prototype makes way more sense than per instance.

Also the `getPrototypeOf` trap is really pointless right now

```js
function Yak() {}
Yak.prototype = new Proxy(Yak.prototype, {
  getPrototypeOf: (target) => console.log('lulz')
});

var yup = new Yak;
Object.getPrototypeOf(yup);
```

The `target` is actually the original `Yak.prototype` which is already the
`yup` prototype: useless trap if used in such way.

Being also unable to distinguish between `getOwnPropertyNames` vs `keys` is
a bit weird.

`Proxy` looks so close to be that powerful but these bits make it kinda
useless for most real-world cases I've been recently dealing with.

Thanks for any sort of improvement.

Regards




On Fri, Mar 18, 2016 at 1:54 PM, Michael Theriot <
michael.lee.ther...@gmail.com> wrote:

> I'm trying to make the proxy-as-a-prototype pattern work but I've just
> discovered the `ownKeys` trap is never called on traps on the prototype. So
> even if the `has` trap is allowed to see the `receiver`, and thus verify
> the properties "0", "1" exist, this pattern would fail to return the
> properties "0", "1" exist on an `Object.getOwnPropertyNames` call.
> Disappointing! I'd rather use a proxy on the prototype than create one for
> each instance but without a correct `ownKeys` return it just doesn't come
> full circle. Is there a trick to make this work or am I out of luck here? I
> can only think of actually defining the properties to make it work, which
> defeats the idea of using a proxy on the prototype to begin with.
>
> Regardless I agree that traps called on a prototype chain should always
> receive the `receiver` as an argument. I think the only trap other than
> `set`, `get`, and `has` that can do this is the `getPrototypeOf` trap
> (currently does not have a `receiver`) when the `instanceof` check needs to
> climb the prototype chain.
>
> On Thu, Mar 17, 2016 at 6:29 PM, Tom Van Cutsem 
> wrote:
>
>> The rationale for not having a `receiver` argument to `has` is that the
>> value produced by the "in" operator is not normally dependent on the
>> receiver. This is in contrast with `get` and `set` which may find an
>> accessor up the proto chain that needs to run with a `this` bound to the
>> receiver.
>>
>> That said, I follow your line of reasoning and it is true that `has`,
>> `get` and `set` are the three traps that can be called on a
>> proxy-used-as-prototype (now that `enumerate` is considered deprecated), so
>> it would be consistent to allow all of them to  refer back to the original
>> receiver. This enables the general pattern that you illustrate.
>>
>> As you note, the weirdness of this is apparent because it doesn't
>> normally make sense to pass a `receiver` argument to Reflect.has().
>> However, if `receiver` would be made visible in a Proxy handler's `has`
>> trap, then `Reflect.has` should nevertheless be likewise extended so that
>> one can faithfully forward the `receiver` argument.
>>
>> Spec-wise, I think the only significant change is that 7.3.10 HasProperty
>> , step
>> 3 must be changed to `O.[[HasProperty]](P, O)` and all [[HasProperty]]
>> internal methods must likewise be extended with an extra argument (which
>> they ignore). Only the Proxy implementation in 9.5.7 would then actually
>> refer to that argument.
>>
>> Cheers,
>> Tom
>>
>> 2016-03-17 11:46 GMT+01:00 Michael Theriot > >:
>>
>>> I feel like it should, or I am misunderstanding something fundamental. I
>>> made a basic scenario to explain:
>>>
>>> ```js
>>> var arrays = new WeakMap();
>>>
>>> function ArrayView(array) {
>>>   arrays.set(this, array);
>>>
>>>   return new Proxy(this, {
>>> set: (target, property, value) => (arrays.has(this) && property in
>>> arrays.get(this))  ? arrays.get(this)[property] = value : target[property]
>>> = value,
>>> get: (target, property)=> (arrays.has(this) && property in
>>> arrays.get(this))  ? arrays.get(this)[property] : target[property],
>>> has: (target, property)=> (arrays.has(this) && property in
>>> arrays.get(this)) || property in target
>>>   });
>>> }
>>>
>>> ArrayView.prototype = Object.create(Array.prototype, {
>>>   arrayLength: {
>>> get() {
>>>   return arrays.get(this).length;
>>> }
>>>   }
>>> });
>>> ```
>>>
>>> When `new ArrayView(somearray)` is called the reference to `somearray`
>>> is stored in the `arrays` weak map and a proxy is returned that allows you
>>> to manipulate indices on it, or fallback to the object for other properties.
>>>
>>> This could be simplified by putting the proxy on the prototype chain to
>>> reduce overhead and actually return a genuine `ArrayView` object instead:
>>>
>>> ```js
>>> var arrays = new WeakMap();
>>>
>>> function ArrayView2(array) {
>>>   arrays.set(this, array);
>>> }
>>>
>>> var protoLayer = 

Re: Proxy handler.has() does not have a receiver argument?

2016-03-18 Thread Michael Theriot
To be clear, I'm not suggesting behavior like `getOwnPropertyNames` be
overridden by anything on the prototype, just a way to use proxies without
having to instantiate identical copies that all use the same handler.

I still believe a proxy on the prototype should always have a `receiver`
sent to each trap, but if I need to return a proxy for each object it
doesn't really matter for the example I made.

On Fri, Mar 18, 2016 at 5:43 PM, Tom Van Cutsem  wrote:

> I was on board with potentially making `has()` receiver-dependent but you
> lost me when you expected `getOwnPropertyNames` to trigger a trap on a
> proxy-as-prototype. Adding `receiver` to every MOP method is a no-go. It
> fundamentally changes the meaning of these operations and it would destroy
> the pay-only-when-you-use-it performance model of proxies, since operations
> that used to be local to only the 'own' object would now need to search the
> proto-chain for a potential proxy trap.
>
> Using a proxy-as-prototype was never intended as a way to be able to
> intercept arbitrary operations on whatever object happened to inherit from
> the proxy. A proxy-as-prototype still emulates only a single object. It
> just happens to be an object that serves as a prototype for other objects.
>
> Cheers,
> Tom
>
> 2016-03-18 23:18 GMT+01:00 Michael Theriot 
> :
>
>> I think I figured out how to make inheritance work...
>>
>> ```js
>> var wm1 = new WeakMap(); function A() { let proxy = new Proxy(this, {
>> get: (target, property, receiver) => property === 'bacon' ||
>> target[property] }); wm1.set(proxy, {}); return proxy; } var wm2 = new
>> WeakMap(); function B() { let proxy = A.call(new Proxy(this, { get:
>> (target, property, receiver) => property === 'ham' || target[property] }));
>> wm2.set(proxy, {}); return proxy; } var a = new A(); var b = new B();
>> wm1.has(a); // true wm2.has(a); // false wm1.has(b); // true wm2.has(b); //
>> true
>>
>> a.bacon; // true
>> a.ham; // undefined
>>
>> b.bacon; // true
>> b.ham; // true
>> ```
>>
>> I can't imagine this is good for optimizations though. But I guess it
>> does what I need.
>>
>> On Fri, Mar 18, 2016 at 4:45 PM, Michael Theriot <
>> michael.lee.ther...@gmail.com> wrote:
>>
>>> Michael’s preferred approach also introduces observable irregularity
 into the standard JS inheritance model for ordinary objects.
 Consider an object created using Michael’s preferred approach:
 ```js
 var arr = [0, 1];
 console.log(Reflect.has(arr,”0”));  //true, arr has “0” as an own
 property
 var subArr = Object.create(arr);
 console.log(Reflect.has(subArr,”0”));  //true, all unshadowed
 properties of proto visible from ordinary objects
 var b = new ArrayView2(arr);
 console.log(Reflect.has(b,”0”));  //true, prototype proxy makes array
 elements visible as if properties of b
 var subB= Object.create(b);
 console.log(Reflect.has(subB,”0”));  //false, some unshadowed
 properties of proto is not visible from subB
 ```
>>>
>>>
>>> I think this relates to the original concern; if you could pass the
>>> receiver this could be resolved. That still leaves `getOwnPropertyNames`
>>> reporting wrong values though and I see no foreseeable way to resolve that
>>> without returning an actual proxy itself.
>>>
>>> The reason I'm trying this approach is because I read on the MDN that
>>> when used in the prototype a `receiver` argument is passed that references
>>> the instance, so I assumed this was the intent behind it. The only other
>>> explanation I could think of is that proxies have a receiver to mimic the
>>> `Reflect.set`/`Reflect.get` methods which need a receiver for
>>> getters/setters to work properly, not so you can use them on the prototype
>>> chain.
>>>
>>> The other case I would make is every instance would have an identical
>>> proxy, and it just makes sense to put that on the prototype for the same
>>> reasons you put shared methods/properties there.
>>>
>>> Note that we are not really talking about a new capability here.
 Michael’s first design shows that ES proxies already have the capability to
 implement the object level semantics he desires.
>>>
>>>
>>> To be fair I had several obstacles with inheritance using the first
>>> version.
>>>
>>> ```js
>>> var wm1 = new WeakMap();
>>>
>>> function A() {
>>>   wm1.set(this, {});
>>>   return new Proxy(this, {});
>>> }
>>>
>>> var wm2 = new WeakMap();
>>>
>>> function B() {
>>>   A.call(this);
>>>   wm2.set(this, {});
>>>   return new Proxy(this, {});
>>> }
>>>
>>> var a = new A();
>>> var b = new B();
>>>
>>> wm1.has(a); // true
>>> wm2.has(a); // false
>>>
>>> wm1.has(b); // false
>>> wm2.has(b); // true
>>> ```
>>>
>>> As you can see storing a reference to `this` can't work anymore, since
>>> we actually return a proxy. You can try to work around this...
>>>
>>> ```js
>>> var wm1 = new WeakMap();
>>>
>>> function A() {
>>>   let self = this;
>>>   

Re: Proxy handler.has() does not have a receiver argument?

2016-03-18 Thread Michael Theriot
I think I figured out how to make inheritance work...

```js
var wm1 = new WeakMap(); function A() { let proxy = new Proxy(this, { get:
(target, property, receiver) => property === 'bacon' || target[property]
}); wm1.set(proxy, {}); return proxy; } var wm2 = new WeakMap(); function
B() { let proxy = A.call(new Proxy(this, { get: (target, property,
receiver) => property === 'ham' || target[property] })); wm2.set(proxy,
{}); return proxy; } var a = new A(); var b = new B(); wm1.has(a); // true
wm2.has(a); // false wm1.has(b); // true wm2.has(b); // true

a.bacon; // true
a.ham; // undefined

b.bacon; // true
b.ham; // true
```

I can't imagine this is good for optimizations though. But I guess it does
what I need.

On Fri, Mar 18, 2016 at 4:45 PM, Michael Theriot <
michael.lee.ther...@gmail.com> wrote:

> Michael’s preferred approach also introduces observable irregularity into
>> the standard JS inheritance model for ordinary objects.
>> Consider an object created using Michael’s preferred approach:
>> ```js
>> var arr = [0, 1];
>> console.log(Reflect.has(arr,”0”));  //true, arr has “0” as an own property
>> var subArr = Object.create(arr);
>> console.log(Reflect.has(subArr,”0”));  //true, all unshadowed properties
>> of proto visible from ordinary objects
>> var b = new ArrayView2(arr);
>> console.log(Reflect.has(b,”0”));  //true, prototype proxy makes array
>> elements visible as if properties of b
>> var subB= Object.create(b);
>> console.log(Reflect.has(subB,”0”));  //false, some unshadowed properties
>> of proto is not visible from subB
>> ```
>
>
> I think this relates to the original concern; if you could pass the
> receiver this could be resolved. That still leaves `getOwnPropertyNames`
> reporting wrong values though and I see no foreseeable way to resolve that
> without returning an actual proxy itself.
>
> The reason I'm trying this approach is because I read on the MDN that when
> used in the prototype a `receiver` argument is passed that references the
> instance, so I assumed this was the intent behind it. The only other
> explanation I could think of is that proxies have a receiver to mimic the
> `Reflect.set`/`Reflect.get` methods which need a receiver for
> getters/setters to work properly, not so you can use them on the prototype
> chain.
>
> The other case I would make is every instance would have an identical
> proxy, and it just makes sense to put that on the prototype for the same
> reasons you put shared methods/properties there.
>
> Note that we are not really talking about a new capability here. Michael’s
>> first design shows that ES proxies already have the capability to implement
>> the object level semantics he desires.
>
>
> To be fair I had several obstacles with inheritance using the first
> version.
>
> ```js
> var wm1 = new WeakMap();
>
> function A() {
>   wm1.set(this, {});
>   return new Proxy(this, {});
> }
>
> var wm2 = new WeakMap();
>
> function B() {
>   A.call(this);
>   wm2.set(this, {});
>   return new Proxy(this, {});
> }
>
> var a = new A();
> var b = new B();
>
> wm1.has(a); // true
> wm2.has(a); // false
>
> wm1.has(b); // false
> wm2.has(b); // true
> ```
>
> As you can see storing a reference to `this` can't work anymore, since we
> actually return a proxy. You can try to work around this...
>
> ```js
> var wm1 = new WeakMap();
>
> function A() {
>   let self = this;
>   if(new.target === A) {
> self = new Proxy(this, {});
>   }
>   wm1.set(self, {});
>   return self;
> }
>
> var wm2 = new WeakMap();
>
> function B() {
>   let self = this;
>   if(new.target === B) {
> self = new Proxy(this, {});
>   }
>   A.call(self);
>   wm2.set(self, {});
>   return self;
> }
>
> var a = new A();
> var b = new B();
>
> wm1.has(a); // true
> wm2.has(a); // false
>
> wm1.has(b); // true
> wm2.has(b); // true
> ```
>
> But then problems arise because the new proxy doesn't go through the old
> proxy. So anything guaranteed by A()'s proxy is not guaranteed by B()'s
> proxy.
>
> ```js
> var wm1 = new WeakMap();
>
> function A() {
>   let self = this;
>   if(new.target === A) {
> self = new Proxy(this, {
>   get: (target, property, receiver) => property === 'bacon' ||
> target[property]
> });
>   }
>   wm1.set(self, {});
>   return self;
> }
>
> var wm2 = new WeakMap();
>
> function B() {
>   let self = this;
>   if(new.target === B) {
> self = new Proxy(this, {
>   get: (target, property, receiver) => property === 'ham' ||
> target[property]
> });
>   }
>   A.call(self);
>   wm2.set(self, {});
>   return self;
> }
>
> var a = new A();
> var b = new B();
>
> wm1.has(a); // true
> wm2.has(a); // false
>
> wm1.has(b); // true
> wm2.has(b); // true
>
> a.bacon; // true
> a.ham; // undefined
>
> b.bacon; // undefined
> b.ham; // true
> ```
>
> (I'm open to solutions on this particular case... One that doesn't require
> me to leak the handler of the A proxy)
>
> Ultimately I can actually achieve both what I want with the ArrayView
> example and 

Re: Proxy [[Construct]]

2015-01-18 Thread Allen Wirfs-Brock
Thanks,

changed it to an assert.

Ideally, you should return this sort of thing using bugs.ecmascript.org.

Allen


On Jan 18, 2015, at 3:21 PM, Tom Schuster wrote:

 The Proxy [[Construct]] method 9.5.14, has the step 7.a
 If target does not have a [[Construct]] internal method, throw a TypeError 
 exception.
 
 But a proxy only has a [[Construct]] internal method when the target has a 
 [[Construct]] internal method. I am not aware that an object can lose an 
 internal method during runtime.
 [[Call]] doesn't have a check like this either. Could this check be turned 
 into an assert?
 
 ___
 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: Proxy objects and collection

2014-09-04 Thread Jason Orendorff
On Tue, Sep 2, 2014 at 1:07 PM, Daurnimator q...@daurnimator.com wrote:
 I'm the maintainer of lua.vm.js[1], which allows Lua code to run in the
 browser.
 I've managed to construct a simple and robust cross-language bridge, so that
 Lua code can interact with Javascript objects.
 When the Lua no longer references the Javascript object, its garbage
 collector notifies me (via the __gc metamethod[2]).
 At this point, I drop the reference to the JS object, and the JS garbage
 collector can collect it if needed.
 However, currently, exposing a Lua function or object to Javascript does not
 have the same ability;
 there is no way (that I know of) to know when Javascript no longer needs
 your object.

 Example use case:
 A Lua script wishes to have a Lua function called on an interval:
 `timerid = window:setInterval(function() window.console:log(ping) end)`
 Later, it wishes to clear the timer:
 `window:clearInterval(timerid)`
 This will stop the function from being called, but I have no way to notify
 Lua that the function can be collected.

If the JS function contains the only strong reference to the Lua
function, then when the JS function is collected, the Lua function
will be collected too. Why isn't that sufficient? Does the Lua runtime
keep a list of all functions or something? What for?

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


Re: Proxy objects and collection

2014-09-02 Thread Brendan Eich

Daurnimator wrote:
So, I'd like to see some sort of trap that is fired when a Proxy is 
collected.
To prevent over specifying how Javascript garbage collectors should 
operate,
I propose that the trap *may* only be called at some *undefined* point 
after the object is not strongly referenced.


What would you need in the way of an argument to be passed to the trap, 
at this later point?


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


Re: Proxy objects and collection

2014-09-02 Thread Brendan Eich

Daurnimator wrote:
On 2 September 2014 14:41, Brendan Eich bren...@mozilla.org 
mailto:bren...@mozilla.org wrote:


Daurnimator wrote:

So, I'd like to see some sort of trap that is fired when a
Proxy is collected.
To prevent over specifying how Javascript garbage collectors
should operate,
I propose that the trap *may* only be called at some
*undefined* point after the object is not strongly referenced.


What would you need in the way of an argument to be passed to the
trap, at this later point?


I'd imagine the proxy itself (which would be `this`).
The trap would not need to return anything.

There might be an argument here for some sort of object id instead of 
the proxy itself, to avoid resurrection?


Indeed we do not want post-mortem resurrection, but any id would have 
the problem too, if it were strongly linked; and would have a similar 
problem if weak.


In terms of LuaVM, can you say very concretely what you need? A handle 
to the LuaVM peer of the proxy, the object the proxy reflects into JS?


I'm not sure if Javascript implementations already deal with this 
elsewhere.


GC is quite involved, and as you suggest, not to be exposed naively to 
JS user code.


Have you seen

http://wiki.ecmascript.org/doku.php?id=strawman:weak_references

which has evolved on es-discuss:

http://esdiscuss.org/topic/what-is-the-status-of-weak-references
http://esdiscuss.org/topic/es6-es7-es8-and-beyond-a-proposed-roadmap

and probably other threads I'm forgetting.

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


Re: Proxy objects and collection

2014-09-02 Thread David Bruant

Le 02/09/2014 20:07, Daurnimator a écrit :
So, I'd like to see some sort of trap that is fired when a Proxy is 
collected.
To prevent over specifying how Javascript garbage collectors should 
operate,
I propose that the trap *may* only be called at some *undefined* point 
after the object is not strongly referenced.
As Brendan said, what you want has been discussed as Weak References on 
the list, not really proxies.


The question of not wanting to over-specify upfront has come in other 
places in the past. Sometimes, even when the spec leaves freedom to 
implementors, it happens that implemetors make some common choices, then 
people rely on the shared browser behavior of that spec-undefined 
functionality. Then, the feature has to be standardized de facto as 
commonly implemented afterwards.


My point here being that not specifying up front does not guarantee that 
the details won't have to be ever specified.

The enumeration order of object keys comes to mind.

I'm not saying that it's what will or even may happen in this case, but 
just remind that leaving things undefined can fire back and generate the 
opposite of what was intended.


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


Re: Proxy objects and collection

2014-09-02 Thread Brendan Eich

Daurnimator wrote:
On 2 September 2014 15:19, Brendan Eich bren...@mozilla.org 
mailto:bren...@mozilla.org wrote:


 Indeed we do not want post-mortem resurrection, but any id would 
have the problem too, if it were strongly linked; and would have a 
similar problem if weak.


Would it?
If the object is freed before the trap, then the trap just gets some 
sort of object id.
Then it can call out to the external resource manager: hey, resource 
id 123 isn't needed any more.

Which could then free it.


That's cool, but what if the id died on the Lua side? You'd have to 
avoid recycling it as another object. That makes it very much like a 
strong reference.



The discussions around security issues are somewhat interesting,
though I think allayed by my proposal of an undefined interval (i.e. 
possibly delayed, or random)

between the reference being dropped, and the finaliser getting called.


The trouble comes when one implementation is first or has the most 
market power. Then developers (intentionally or not, doesn't matter) 
come to depend on its implementation-defined interval.


The next-event-loop-turn thinking I remember from the weak refs threads 
may be ok. I don't think there's a fast path for proxies, though. Weak 
refs are wanted in ES7 or whatever annual edition after it that they fit in.


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


Re: Proxy objects and collection

2014-09-02 Thread Daurnimator
On 2 September 2014 16:40, Brendan Eich bren...@mozilla.org wrote:
 Daurnimator wrote:
 If the object is freed before the trap, then the trap just gets some
sort of object id.
 Then it can call out to the external resource manager: hey, resource id
123 isn't needed any more.
 Which could then free it.

 That's cool, but what if the id died on the Lua side? You'd have to avoid
recycling it as another object. That makes it very much like a strong
reference.

I don't think I understand what you mean here?
Lua will hold onto the object until it is told it can let go.
If (for some reason) the lua vm is destroyed, then the other traps will fail
e.g. the `get()` trap could `throw VM not available`

I should note here that this is not unique to lua.vm.js.
I could easily come up with cases where a WebWorker would want to know when
the main thread was done with an object.


 The discussions around security issues are somewhat interesting,
 though I think allayed by my proposal of an undefined interval (i.e.
possibly delayed, or random)
 between the reference being dropped, and the finaliser getting called.

 The trouble comes when one implementation is first or has the most market
power. Then developers (intentionally or not, doesn't matter) come to
depend on its implementation-defined interval.

One of the 'tricks' I had in mind was that we already have this 'undefined'
amount of time behaviour in the browser today;
It just happens to be 'never'!

For the current/old use case of Javascript where the VM is regularly thrown
away, these memory leaks don't matter that much.
But looking to the future, knowing about collection at some undetermined
point in the future would be nice :)


 The next-event-loop-turn thinking I remember from the weak refs threads
may be ok. I don't think there's a fast path for proxies, though. Weak refs
are wanted in ES7 or whatever annual edition after it that they fit in.

That sounds like a okay choice, but wouldn't this mean browsers have to run
a full gc every time they get back to their main loop?
This would seem undesirable.

Is it bad to wait and see what the browser authors do, and then just
standardize on that?
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Proxy objects and collection

2014-09-02 Thread Brendan Eich

Daurnimator wrote:
On 2 September 2014 16:40, Brendan Eich bren...@mozilla.org 
mailto:bren...@mozilla.org wrote:

 Daurnimator wrote:
 If the object is freed before the trap, then the trap just gets 
some sort of object id.
 Then it can call out to the external resource manager: hey, 
resource id 123 isn't needed any more.

 Which could then free it.

 That's cool, but what if the id died on the Lua side? You'd have to 
avoid recycling it as another object. That makes it very much like a 
strong reference.


I don't think I understand what you mean here?
Lua will hold onto the object until it is told it can let go.


Oh, if you hang onto the object on the Lua side just because there's a 
reflecting Proxy for JS, even though there may be zero JS refs, then 
you'll indeed keep the id alive and not have replay bugs.


But in this case I believe you will have memory leaks, due to Lua 
waiting for JS GC when it could know the object lost all JS refs and 
*then* died from loss of Lua refs.


We've had these in Mozilla code using C++ and JS heaps to refer to C++ 
objects and their JS wrappers. We fixed them by being sufficient eager 
no matter which side's refs die first.



I should note here that this is not unique to lua.vm.js.
I could easily come up with cases where a WebWorker would want to know 
when the main thread was done with an object.


Yes, and if the worker is process-isolated there is a distributed GC 
problem.


But when workers are threads in one process (on most browsers today?), 
it's easier.


That sounds like a okay choice, but wouldn't this mean browsers have 
to run a full gc every time they get back to their main loop?

This would seem undesirable.


I think not -- GCs are not only generational but incremental -- or 
heading that way. So they should be able to collect often, in increments.


Is it bad to wait and see what the browser authors do, and then just 
standardize on that?


No, see the bad game theory I outlined. Winner takes all and spec 
follows that, which overspecifies GC.


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


Re: Proxy .__proto__ is not getPrototypeOf?

2014-05-05 Thread Andrea Giammarchi
not sure I understand but ...

 that makes no sense as hasProxyAsProto is not a Proxy

it's inheriting from a Proxy so where is the surprise? it does what I'd
expect it to do, pass through the inherited Proxy same as you pass through
inherited get/set methods when creating from an object that has get/set
behaviors

Moreover, since you inheriting a proxy that reacts on accessors you have
the right behavior when you access `__proto__`, the `target.__proto__`
should be returned instead.

Last, but not least, `__proto__` is an `Object.prototype` property that has
nothing to do with `Object.getPrototypeOf`  you can redefine
`__proto__` behavior either in the `Object.prototype` itself, through a
proxy, or within an object, but that won't affect returned value of
`Object.getPrototypeOf`

```javascript
var o = {};
Object.defineProperty(o, '__proto__', {
  get: function () {
return String.prototype;
  }
});

o.__proto__ === String.prototype;
Object.getPrototypeOf(o); // Object.prototype
```

Best Regards



On Mon, May 5, 2014 at 10:40 AM, John Barton johnjbar...@google.com wrote:

 I'm hoping someone can explain this result which surprises me.

 If I create an object with a Proxy-ed prototype, the resulting object does
 not obey .__proto__ equal Object.getPrototypeOf().

 For example:
   var aPrototype = {foo: 'foo'};
   var handler = {
   get: function(target, name, receiver) {
   console.log('   (Proxy handler \'get\' called for name = ' + name +
 ')');
   return target[name];
   }
   };
   var aProxy = Proxy(aPrototype, handler);
   var hasProxyAsProto = Object.create(aProxy);

 At this point, I expected
   hasProxyAsProto.__proto__ === aProxy
 but it it not true.  Moreover, the operation
   hasProxyAsProto.__proto__
 calls the Proxy handler get function with name === '__proto__': that makes
 no sense as hasProxyAsProto is not a Proxy.

 I tried this on Firefox 29 and Chrome 36.  Complete example is here:
 https://gist.github.com/johnjbarton/f8a837104f0292fa088c

 Any ideas?
 jjb

 ___
 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: Proxy .__proto__ is not getPrototypeOf?

2014-05-05 Thread Allen Wirfs-Brock

On May 5, 2014, at 10:40 AM, John Barton wrote:

 I'm hoping someone can explain this result which surprises me.
 
 If I create an object with a Proxy-ed prototype, the resulting object does 
 not obey .__proto__ equal Object.getPrototypeOf().
 
 For example:
   var aPrototype = {foo: 'foo'};
   var handler = {
 get: function(target, name, receiver) {
   console.log('   (Proxy handler \'get\' called for name = ' + name + 
 ')');
   return target[name];

the above line needs to be:
 return Reflect.get(target, name, receiver);

Object.prototype.__proto__ is an accessor property and to work correctly it 
needs to have the originally accessed object passed at the this value.  That's 
why 'get' handlers (and others) have a 'receiver' argument.




 }
   };
   var aProxy = Proxy(aPrototype, handler);
   var hasProxyAsProto = Object.create(aProxy);
 
 At this point, I expected 
   hasProxyAsProto.__proto__ === aProxy
 but it it not true.  Moreover, the operation 
   hasProxyAsProto.__proto__
 calls the Proxy handler get function with name === '__proto__': that makes no 
 sense as hasProxyAsProto is not a Proxy.
 
 I tried this on Firefox 29 and Chrome 36.  Complete example is here: 
 https://gist.github.com/johnjbarton/f8a837104f0292fa088c

I can't speak to the correctness of those implementations but you need to have 
change for it to even have a chance of working.

Allen

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


Re: Proxy .__proto__ is not getPrototypeOf?

2014-05-05 Thread Tom Van Cutsem
2014-05-05 19:40 GMT+02:00 John Barton johnjbar...@google.com:

 I'm hoping someone can explain this result which surprises me.

 If I create an object with a Proxy-ed prototype, the resulting object does
 not obey .__proto__ equal Object.getPrototypeOf().


There's no such equivalence, even for regular objects. `__proto__` is just
a property name, so `proxy.__proto__` just triggers the get trap, as any
normal property access. If the proxy should treat it specially, you need to
special-case the name `__proto__` in the get trap. However, as Allen
points out, forwarding should work correctly as long as you also forward
the receiver binding using the Reflect.get method.


 At this point, I expected
   hasProxyAsProto.__proto__ === aProxy
 but it it not true.  Moreover, the operation
   hasProxyAsProto.__proto__
 calls the Proxy handler get function with name === '__proto__': that makes
 no sense as hasProxyAsProto is not a Proxy.


If an object inherits from a proxy, then any property access for a non-own
property will traverse the prototype chain. If it hits a proxy, that
proxy's get trap is called.

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


Re: Proxy .__proto__ is not getPrototypeOf?

2014-05-05 Thread John Barton
On Mon, May 5, 2014 at 11:44 AM, Allen Wirfs-Brock al...@wirfs-brock.comwrote:


 On May 5, 2014, at 10:40 AM, John Barton wrote:

 I'm hoping someone can explain this result which surprises me.

 If I create an object with a Proxy-ed prototype, the resulting object does
 not obey .__proto__ equal Object.getPrototypeOf().

 For example:
   var aPrototype = {foo: 'foo'};
   var handler = {
   get: function(target, name, receiver) {
   console.log('   (Proxy handler \'get\' called for name = ' + name +
 ')');
   return target[name];


 the above line needs to be:
  return Reflect.get(target, name, receiver);

 Object.prototype.__proto__ is an accessor property and to work correctly
 it needs to have the originally accessed object passed at the this value.
  That's why 'get' handlers (and others) have a 'receiver' argument.


Thanks! With your change the example works. Unfortunately I'm still
confused.

Before I reduced the code to a short example I was using
Object.getPrototypeOf(obj), like:
  https://gist.github.com/johnjbarton/30c3e72d51d9d64e36d1
rather than targt[name] my first examples shows. It also fails the same
way.

Let me rephrase my question: why is the Proxy get even called in this case?

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


Re: Proxy .__proto__ is not getPrototypeOf?

2014-05-05 Thread Boris Zbarsky

On 5/5/14, 4:21 PM, John Barton wrote:

Let me rephrase my question: why is the Proxy get even called in this case?


Because the way __proto__ works is as if the JS implementation had done:

(function() {
  protoGetter = Object.getPrototypeOf;
  Object.defineProperty(Object.prototype, __proto__,
{
   set: function() { /* magic here */ },
   get: function() { return protoGetter(this); }
});
})();

before any page script got to run.

Which means that __proto__ is a simple accessor property on 
Object.prototype.  On the one hand, that means that by default it 
appears on all objects.  On the other hand it means it can be shadowed, 
for example by someone doing an explicit defineProperty for that 
property name on some object.


But it can also be shadowed by proxies, because those get to intercept 
_all_ property access.  So when a obj.__proto__ get happens the 
implementation walks up the proto chain of obj looking for a proxy or 
an object with an own property named __proto__.  If a proxy is found, 
its get() is invoked and that's all there is to do as far as the 
implementation is concerned.  If an own property named __proto__ is 
found, then the implementation checks whether it's an accessor or value 
property, and either returns the value or calls the getter, depending on 
which sort it is.


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


Re: Proxy .__proto__ is not getPrototypeOf?

2014-05-05 Thread Andrea Giammarchi
but that's exactly what I've replied to you already?

Once again, `__proto__` is spec'd in the `Object.prototype` like this:

```javascript

Object.defineProperty(
  Object.prototype,
  '__proto__',
  {
configurable: true,
get: function () {
  return Object.getPrototypeOf(this);
},
set: function (proto) {
  Object.setPrototypeOf(this, proto);
}
  }
);

```

the only exception to that specification is as literal syntax so that
`{__proto__:[]}` is instanceof Array but `{__proto__:[]}` is not ... that
is the only magic about the property, everything else passes through the
`Object.prototype`

Best Regards




On Mon, May 5, 2014 at 1:36 PM, John Barton johnjbar...@google.com wrote:

 Thanks, Boris, this explanation solves the puzzle for me.


 On Mon, May 5, 2014 at 1:32 PM, Boris Zbarsky bzbar...@mit.edu wrote:

 On 5/5/14, 4:21 PM, John Barton wrote:

 Let me rephrase my question: why is the Proxy get even called in this
 case?


 Because the way __proto__ works is as if the JS implementation had done:

 (function() {
   protoGetter = Object.getPrototypeOf;
   Object.defineProperty(Object.prototype, __proto__,
 {
set: function() { /* magic here */ },
get: function() { return protoGetter(this); }
 });
 })();

 before any page script got to run.

 Which means that __proto__ is a simple accessor property on
 Object.prototype.  On the one hand, that means that by default it appears
 on all objects.  On the other hand it means it can be shadowed, for example
 by someone doing an explicit defineProperty for that property name on some
 object.

 But it can also be shadowed by proxies, because those get to intercept
 _all_ property access.  So when a obj.__proto__ get happens the
 implementation walks up the proto chain of obj looking for a proxy or an
 object with an own property named __proto__.  If a proxy is found, its
 get() is invoked and that's all there is to do as far as the implementation
 is concerned.  If an own property named __proto__ is found, then the
 implementation checks whether it's an accessor or value property, and
 either returns the value or calls the getter, depending on which sort it is.

 -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


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


Re: Proxy .__proto__ is not getPrototypeOf?

2014-05-05 Thread Andrea Giammarchi
 everything else passes through the `Object.prototype`

of course, unless not intercepted or shadowed as shown already in my
previous reply ... `Object.defineProperty(anyObject, '__proto__', {value:
false})`


On Mon, May 5, 2014 at 4:57 PM, Andrea Giammarchi 
andrea.giammar...@gmail.com wrote:

 but that's exactly what I've replied to you already?

 Once again, `__proto__` is spec'd in the `Object.prototype` like this:

 ```javascript

 Object.defineProperty(
   Object.prototype,
   '__proto__',
   {
 configurable: true,
 get: function () {
   return Object.getPrototypeOf(this);
 },
 set: function (proto) {
   Object.setPrototypeOf(this, proto);
 }
   }
 );

 ```

 the only exception to that specification is as literal syntax so that
 `{__proto__:[]}` is instanceof Array but `{__proto__:[]}` is not ... that
 is the only magic about the property, everything else passes through the
 `Object.prototype`

 Best Regards




 On Mon, May 5, 2014 at 1:36 PM, John Barton johnjbar...@google.comwrote:

 Thanks, Boris, this explanation solves the puzzle for me.


 On Mon, May 5, 2014 at 1:32 PM, Boris Zbarsky bzbar...@mit.edu wrote:

 On 5/5/14, 4:21 PM, John Barton wrote:

 Let me rephrase my question: why is the Proxy get even called in this
 case?


 Because the way __proto__ works is as if the JS implementation had done:

 (function() {
   protoGetter = Object.getPrototypeOf;
   Object.defineProperty(Object.prototype, __proto__,
 {
set: function() { /* magic here */ },
get: function() { return protoGetter(this); }
 });
 })();

 before any page script got to run.

 Which means that __proto__ is a simple accessor property on
 Object.prototype.  On the one hand, that means that by default it appears
 on all objects.  On the other hand it means it can be shadowed, for example
 by someone doing an explicit defineProperty for that property name on some
 object.

 But it can also be shadowed by proxies, because those get to intercept
 _all_ property access.  So when a obj.__proto__ get happens the
 implementation walks up the proto chain of obj looking for a proxy or an
 object with an own property named __proto__.  If a proxy is found, its
 get() is invoked and that's all there is to do as far as the implementation
 is concerned.  If an own property named __proto__ is found, then the
 implementation checks whether it's an accessor or value property, and
 either returns the value or calls the getter, depending on which sort it is.

 -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



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


Re: Proxy .__proto__ is not getPrototypeOf?

2014-05-05 Thread John Barton
Since you ask for a response:


On Mon, May 5, 2014 at 11:30 AM, Andrea Giammarchi 
andrea.giammar...@gmail.com wrote:

 not sure I understand but ...

  that makes no sense as hasProxyAsProto is not a Proxy

 it's inheriting from a Proxy so where is the surprise? it does what I'd
 expect it to do, pass through the inherited Proxy same as you pass through
 inherited get/set methods when creating from an object that has get/set
 behaviors


I was incorrectly assuming that the proto chain would not be consulted for
__proto__: it would be found on every object. Boris' post described the
mechanism of __proto__, then I could see why the get operation traversed
the proto chain and thus why my proxy's getter was called. (IMO, having a
getter high on the proto chain that uses 'this' (receiver) to return values
only known to the 'this' object is pretty evil business, even among
notoriously dubious functions like getters.)

May I suggest that trying to guess why someone is surprised is a better
strategy than telling them that you are not surprised.



 Moreover, since you inheriting a proxy that reacts on accessors you have
 the right behavior when you access `__proto__`, the `target.__proto__`
 should be returned instead.


This makes no sense to me, sorry. Since `target`  is already obj.__proto__,
target.__proto__ should not be returned.



 Last, but not least, `__proto__` is an `Object.prototype` property that
 has nothing to do with `Object.getPrototypeOf`  you can redefine
 `__proto__` behavior either in the `Object.prototype` itself, through a
 proxy, or within an object, but that won't affect returned value of
 `Object.getPrototypeOf`


Fine but not relevant: the code I am analyzing would, absent my proxy,
always give the same result for Object.getPrototypeOf and __proto__.  Sure
these could be different, but in reality it doe not happen because too much
code relies on these being the same.


 ```javascript
 var o = {};
 Object.defineProperty(o, '__proto__', {
   get: function () {
 return String.prototype;
   }
 });

 o.__proto__ === String.prototype;
 Object.getPrototypeOf(o); // Object.prototype
 ```

 Best Regards



 On Mon, May 5, 2014 at 10:40 AM, John Barton johnjbar...@google.comwrote:

 I'm hoping someone can explain this result which surprises me.

 If I create an object with a Proxy-ed prototype, the resulting object
 does not obey .__proto__ equal Object.getPrototypeOf().

 For example:
   var aPrototype = {foo: 'foo'};
   var handler = {
   get: function(target, name, receiver) {
   console.log('   (Proxy handler \'get\' called for name = ' + name +
 ')');
   return target[name];
   }
   };
   var aProxy = Proxy(aPrototype, handler);
   var hasProxyAsProto = Object.create(aProxy);

 At this point, I expected
   hasProxyAsProto.__proto__ === aProxy
 but it it not true.  Moreover, the operation
   hasProxyAsProto.__proto__
 calls the Proxy handler get function with name === '__proto__': that
 makes no sense as hasProxyAsProto is not a Proxy.

 I tried this on Firefox 29 and Chrome 36.  Complete example is here:
 https://gist.github.com/johnjbarton/f8a837104f0292fa088c

 Any ideas?
 jjb

 ___
 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: Proxy .__proto__ is not getPrototypeOf?

2014-05-05 Thread Andrea Giammarchi
that code is wrong and I don't know why or who would assume that
accordingly with specs

I'd rather file a bug in there, pointing at specs ... there are two places
about __proto__, everything else/other interpretations are evil indeed

take care


On Mon, May 5, 2014 at 6:48 PM, John Barton johnjbar...@google.com wrote:

 Since you ask for a response:


 On Mon, May 5, 2014 at 11:30 AM, Andrea Giammarchi 
 andrea.giammar...@gmail.com wrote:

 not sure I understand but ...

  that makes no sense as hasProxyAsProto is not a Proxy

 it's inheriting from a Proxy so where is the surprise? it does what I'd
 expect it to do, pass through the inherited Proxy same as you pass through
 inherited get/set methods when creating from an object that has get/set
 behaviors


 I was incorrectly assuming that the proto chain would not be consulted for
 __proto__: it would be found on every object. Boris' post described the
 mechanism of __proto__, then I could see why the get operation traversed
 the proto chain and thus why my proxy's getter was called. (IMO, having a
 getter high on the proto chain that uses 'this' (receiver) to return values
 only known to the 'this' object is pretty evil business, even among
 notoriously dubious functions like getters.)

 May I suggest that trying to guess why someone is surprised is a better
 strategy than telling them that you are not surprised.



 Moreover, since you inheriting a proxy that reacts on accessors you have
 the right behavior when you access `__proto__`, the `target.__proto__`
 should be returned instead.


 This makes no sense to me, sorry. Since `target`  is already
 obj.__proto__, target.__proto__ should not be returned.



 Last, but not least, `__proto__` is an `Object.prototype` property that
 has nothing to do with `Object.getPrototypeOf`  you can redefine
 `__proto__` behavior either in the `Object.prototype` itself, through a
 proxy, or within an object, but that won't affect returned value of
 `Object.getPrototypeOf`


 Fine but not relevant: the code I am analyzing would, absent my proxy,
 always give the same result for Object.getPrototypeOf and __proto__.  Sure
 these could be different, but in reality it doe not happen because too much
 code relies on these being the same.


 ```javascript
 var o = {};
 Object.defineProperty(o, '__proto__', {
   get: function () {
 return String.prototype;
   }
 });

 o.__proto__ === String.prototype;
 Object.getPrototypeOf(o); // Object.prototype
 ```

 Best Regards



 On Mon, May 5, 2014 at 10:40 AM, John Barton johnjbar...@google.comwrote:

 I'm hoping someone can explain this result which surprises me.

 If I create an object with a Proxy-ed prototype, the resulting object
 does not obey .__proto__ equal Object.getPrototypeOf().

 For example:
   var aPrototype = {foo: 'foo'};
   var handler = {
   get: function(target, name, receiver) {
   console.log('   (Proxy handler \'get\' called for name = ' + name +
 ')');
   return target[name];
   }
   };
   var aProxy = Proxy(aPrototype, handler);
   var hasProxyAsProto = Object.create(aProxy);

 At this point, I expected
   hasProxyAsProto.__proto__ === aProxy
 but it it not true.  Moreover, the operation
   hasProxyAsProto.__proto__
 calls the Proxy handler get function with name === '__proto__': that
 makes no sense as hasProxyAsProto is not a Proxy.

 I tried this on Firefox 29 and Chrome 36.  Complete example is here:
 https://gist.github.com/johnjbarton/f8a837104f0292fa088c

 Any ideas?
 jjb

 ___
 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: Proxy-for-array transparency issues

2013-07-31 Thread Tom Van Cutsem
2013/7/31 Allen Wirfs-Brock al...@wirfs-brock.com


 We could define a new predicate Array.isArrayLike with a proxy friendly
 extensions mechanism (@@isArrayLike).  It wouldn't be the same test as
 Array.isArray and the result would be more a statement of intent than an
 absolute guarantee.

 Would anybody use it? Would it's existence be enough to eliminate the
 Array.isArray/proxy concern?


Adding yet another function doesn't solve the problem: there is extant ES5
code out there that uses Array.isArray. It will fail on proxies-for-arrays,
even when those proxies-for-arrays would be perfectly substitutable for
actual arrays (e.g. membraned arrays).

Here's a contrived example where a function behaves differently depending
on whether you pass it an array or not:

// call makePoint( [ x, y] ) to construct a new Point(x,y)
// call makePoint(x) to construct a new Point(x,x)
function makePoint(arg) {
  if (Array.isArray(arg)) {
return new Point(arg[0], arg[1]);
  } else {
return new Point(arg, arg);
  }
}

While looking for Array.isArray on GitHub I found an example of an
in-the-wild function that does this kind of argument-inspection (even twice
in the same function):

https://github.com/cnicq/DB/blob/1f3a88501f819378ec7919b5f87d20bbd98da5a7/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/repl_set/strategies/statistics_strategy.js#L19


In particular, this line of code looks like a common idiom when you want to
abstract over dealing with either 1 or many things:

var tagObjects = Array.isArray(tags) ? tags : [tags];
// then do a for-loop over the array


Given that ES6 will allow users to create subclasses of Array, where
subclass instances will be branded as arrays, Array.isArray's contract will
already become more diluted. In that light, I don't see the problem
with Array.isArray(proxyForArray) returning `true`.

On the flip side: DOM nodelists, while behaviorally similar to arrays, also
don't pass the Array.isArray test. Does this anger developers? Or is this
common wisdom and people have learned to live with the differences between
nodelists and arrays?

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


Re: Proxy-for-array transparency issues

2013-07-31 Thread Erik Arvidsson
On Jul 31, 2013 6:40 AM, Tom Van Cutsem tomvc...@gmail.com wrote:

 On the flip side: DOM nodelists, while behaviorally similar to arrays,
also don't pass the Array.isArray test. Does this anger developers? Or is
this common wisdom and people have learned to live with the differences
between nodelists and arrays?

Yes, but mostly it is because NodeList etc do not have Array.prototype on
the prototype chain. ___
 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: Proxy-for-array transparency issues

2013-07-30 Thread Allen Wirfs-Brock

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

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. 

 Even then, I wouldn't be sure to understand. Which part of ES5.1 are you 
 referring to?
 I believe a code snippet to explain would make things easier to understand.

In ES5 some of this is subtle, for example  in the introduction to 15.9.5 
(Properties of Date Prototuype Object) is this paragrpah:

In following descriptions of functions that are properties of the Date 
prototype object, the phrase “this Date object” refers to the object that is 
the this value for the invocation of the function. Unless explicitly noted 
otherwise, none of these functions are generic; a TypeError exception is thrown 
if the this value is not an object for which the value of the [[Class]] 
internal property is Date. Also, the phrase “this time value” refers to the 
Number value for the time represented by this Date object, that is, the value 
of the [[PrimitiveValue]] internal property of this Date object.

and each Date.prototype method starts with a step like:
1.  Let t be this time value.

What this is really saying is that this method only works on object instances 
that have the internal layout created by the Date constructor. 

For a broader discussion of the use of [[Class]] in ES5 see 
https://docs.google.com/document/d/1sSUtri6joyOOh23nVDfMbs1wDS7iDMDUFVVeHeRdSIw/edit?hl=enauthkey=CI-FopgCpli=1
 


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

Re: Proxy-for-array transparency issues

2013-07-30 Thread David Bruant
2013/7/30 Allen Wirfs-Brock al...@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:

 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)

 By this object reference, are you talking about the this keyword?


 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.




 Even then, I wouldn't be sure to understand. Which part of ES5.1 are you
 referring to?
 I believe a code snippet to explain would make things easier to understand.


 In ES5 some of this is subtle, for example  in the introduction to 15.9.5
 (Properties of Date Prototuype Object) is this paragrpah:

 In following descriptions of functions that are properties of the Date
 prototype object, the phrase “this Date object” refers to the object that
 is the this value for the invocation of the function. Unless explicitly
 noted otherwise, none of these functions are generic; a TypeError exception
 is thrown if the this value is not an object for which the value of the
 [[Class]] internal property is Date. Also, the phrase “this time value”
 refers to the Number value for the time represented by this Date object,
 that is, the value of the [[PrimitiveValue]] internal property of this Date
 object.

 and each Date.prototype method starts with a step like:

 1. Let t be this time value.


 What this is really saying is that this method only works on object
 instances that have the internal layout created by the Date constructor.

There is no really saying. There is saying, there are implementations
that rely on this saying of the spec and since the saying is changing
(admittedly somewhere else in the spec), they'll have to adapt their
implementation to take into account the new sayings.
I'm not sure worrying about implementations is helpful in this debate. This
is a low-level feature. A good test suite applying built-in algorithms to
proxies will go a long way preventing implementation issues.



 For a broader discussion of the use of [[Class]] in ES5 see
 https://docs.google.com/document/d/1sSUtri6joyOOh23nVDfMbs1wDS7iDMDUFVVeHeRdSIw/edit?hl=enauthkey=CI-FopgCpli=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.


 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 

Re: Proxy-for-array transparency issues

2013-07-30 Thread Tom Van Cutsem
tl;dr:

I would argue that Array.isArray should return true for proxies-for-arrays.
The other built-ins are less crucial and could stay the way they are.


Summarizing the previous discussion:
- I agree that it is not safe to generalize: a proxy for an X is not in
general substitutable for X.
- It follows that having proxies-for-X pass all tests of the form if O is
an exotic X is undesirable.
- Hence, we should look at each of the tests and decide on a case-by-case
basis whether proxies can be permitted.

For the specific case of arrays, let's go over the list again:

 * Array.isArray
 We've discussed the meaning of this in the past and have agreed that it
 should be considered a test for exotic array-ness and in particular the
 length invariant. A Proxy whose target is an exotic array may or may not
 qualify. We could add a @@isArray tag, but I'm not convinced that it is
 really needed.


David's point about membranes being broken if Array.isArray(membranedArray)
returns false is a valid point. It means code outside a membrane will
observe all arrays inside the membrane as ordinary objects. This breaks
transparency quite badly.

Even with a custom proxy handler, membranes would not be able to fix this,
unless the membrane abstraction itself patches Array.isArray to recognize
its own membrane wrappers. The problem is not that array generics won't
work on wrapped arrays, it's that wrapped arrays have lost their isArray
brand.

As far as I can tell, the only real array invariant is
that Array.isArray(obj) currently implies that obj must have a
non-configurable data property named length that holds a number.

But we're in luck: since length is non-configurable on arrays, and since
direct proxies were carefully specced such that they could not violate
non-configurability of target properties, a proxy-for-array will be obliged
to return a valid length value as well. Hence having
Array.isArray(proxyForArray) return true makes sense.

Having a user-customizable @@isArray tag seems a bridge too far because
then we'd lose the invariant that Array.isArray tests for. But having
Array.isArray return true for exotic arrays *and only* proxies whose target
is an exotic array seems both safe and useful.


  * Array.prototype.concat
 As currently spec'ed the [[Class]] test has been replaced with an exotic
 array test on the this value (supporting creating subclass instances) and a
 IsConcatSpreadable abstract operation (defined in terms of
 @@isConcatSpreadable) falling back to an exotic array test) used to decide
 whether to spread argument values.
 To make concat spread a proxied array you would have to explicitly define
 the @@isConcatSpreadable property of the target object.  To maintain legacy
 computability with objects inheriting from Array.prototype we can't just
 have include @@isConcatSpreadable on Array.prototype.
 There may be other teaks we could do.  But we talked about concat at last
 weeks meeting WRT Typed Arrays and concluded that concat is pretty bogus
 and it may be a turd that is not worth polishing.


Sorry, I was looking at jorendorff's online ES6 draft which did not include
this extensibility hook yet. It seems the @@isConcatSpreadable hook is
sufficient for proxies-for-arrays to allow themselves to be spread. Good!

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


I agree. This would be a rare use case, and the issue is broader than just
proxies anyway (e.g. allowing any iterable).


 The other use case is when deciding whether to use { } or [ ] notation to
 encode the object.  The exotic array test  is the right one for ES5
 compatibility.   The appropriate JSON encoding  of a Proxy that has an
 exotic array target is going to be application dependent.   JSON.parse
 already has an extensibility hook (toJSON) that presumably should be
 sufficient to deal with such objects.


I didn't think of the toJSON() hook. That should work, at the cost of
giving up some transparency since `[].toJSON` returns undefined while
`proxyForArray.toJSON` would need to return a function.


  * JSON.parse
 I believe that this [[Class]]==Array (now is exotic array) test is only
 applied to objects created by evaluating the JSON text as if it was an
 object literal.  Such objects will never be proxies.


Agreed.


  * ArrayBuffer.isView
 yup.  The use cases for isView aren't all that clear to me.  It could be
 expressed a @@isView test if it has important use cases.


I'm not familiar enough with ArrayBuffers to understand the consequences.
By analogy with Array.isArray, if a proxy-for-arraybuffer automatically
upholds all observable invariants of ArrayBuffers, then arguably the 

Re: Proxy-for-array transparency issues

2013-07-30 Thread André Bargull

/   * ArrayBuffer.isView
//  yup.  The use cases for isView aren't all that clear to me.  It could be
//  expressed a @@isView test if it has important use cases.
/

I'm not familiar enough with ArrayBuffers to understand the consequences.
By analogy with Array.isArray, if a proxy-for-arraybuffer automatically
upholds all observable invariants of ArrayBuffers, then arguably the test
should return true for proxies. What would be the observable invariants of
an ArrayBuffer?


ArrayBuffer.isView() should not return `true` for exotic array objects. 
That was just a spec bug, fixed in rev16 
(https://bugs.ecmascript.org/show_bug.cgi?id=1570).
As currently spec'ed, ArrayBuffer.isView() only returns true for 
TypedArray objects and DataView objects (both kind of objects have got a 
[[ViewedArrayBuffer]] internal data property). And there are no 
observable invariants which can be used for this case.



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


Re: Proxy-for-array transparency issues

2013-07-30 Thread David Bruant
2013/7/30 Tom Van Cutsem tomvc...@gmail.com

 tl;dr:

 I would argue that Array.isArray should return true for proxies-for-arrays.
 The other built-ins are less crucial and could stay the way they are.

What about WeakMaps? Maps? Sets?
How is the line drawn between crucial and less crucial? How is going to
be decided whether new exotic object types are crucial?
I feel the line is very context-specific. I can easily agree that arrays
are more used than other exotic objects *for now* (WeakMap/Map/Set may
change that, we'll see), but a Date enhancing library will want to work
with proxies (proxies it does not have necessarily created), and it will
become crucial for proxies-on-dates to work there.
Importance is relative to context and doing a common denominator analysis
to assess importance can be detrimental for specific use cases.


I agree that it is not safe to generalize: a proxy for an X is not in
general substitutable for X.
= How much unsafe? What are the risks? (implementation concerns don't
apply. Let's solve this with tests. Implementors can also add assertions,
very much as they do today anyway [1])
A built-in algorithm will misbehave? I think that all of them don't have
side-effects beyond the objects being acted upon. Worst case, it will
throw, which is a regular risk anyway for a lot of built-in algorithms
anyway.
This risk already exists if an Array.prototype method is applied to an
object with funky getter/setters (for length or numerical properties).

David

[1] http://dbaron.org/log/20130729-debug-builds
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Proxy-for-array transparency issues

2013-07-30 Thread Tom Van Cutsem
2013/7/30 David Bruant bruan...@gmail.com

 2013/7/30 Tom Van Cutsem tomvc...@gmail.com

 tl;dr:

 I would argue that Array.isArray should return true for
 proxies-for-arrays.
 The other built-ins are less crucial and could stay the way they are.

 What about WeakMaps? Maps? Sets?


I meant the specific list of built-in methods on Array, apart from isArray,
are less crucial.

We'll have to evaluate the other types you mention on a case-by-case basis
as well.


 How is the line drawn between crucial and less crucial? How is going
 to be decided whether new exotic object types are crucial?
 I feel the line is very context-specific.


I think that's essentially Allen's point: with built-ins, you arrive at
rock-bottom, at the edges of the platform. You cannot easily generalize
anymore. We need to look at each of these is an exotic X tests on a
case-by-case basis and use our judgment whether it makes sense for proxies
to pass the test.


 I can easily agree that arrays are more used than other exotic objects
 *for now* (WeakMap/Map/Set may change that, we'll see), but a Date
 enhancing library will want to work with proxies (proxies it does not have
 necessarily created), and it will become crucial for proxies-on-dates to
 work there.
 Importance is relative to context and doing a common denominator
 analysis to assess importance can be detrimental for specific use cases.


 I agree that it is not safe to generalize: a proxy for an X is not in
 general substitutable for X.
 = How much unsafe? What are the risks?


I don't think a general answer exists, because each of these built-ins has
its own idiosyncratic set of invariants.

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


Re: Proxy-for-array transparency issues

2013-07-30 Thread Allen Wirfs-Brock

On Jul 30, 2013, at 1:25 AM, David Bruant wrote:

 
 2013/7/30 Allen Wirfs-Brock al...@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=enauthkey=CI-FopgCpli=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 

Re: Proxy-for-array transparency issues

2013-07-30 Thread David Bruant

Le 30/07/2013 18:57, Allen Wirfs-Brock a écrit :
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.
I could not agree more. Should proxies be deferred waiting for private 
data, then?
Or, maybe they can be put in quarantaine in some way. For instance, 
making the constructor throw if the target isn't a regular object. 
That's for the time being until the private state (whether private 
internal slots or user data) is sorted out. A max-min sort of proxy, I 
guess.




...



For a broader discussion of the use of [[Class]] in ES5 see

https://docs.google.com/document/d/1sSUtri6joyOOh23nVDfMbs1wDS7iDMDUFVVeHeRdSIw/edit?hl=enauthkey=CI-FopgCpli=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.
I was answering to your concern about built-in implementations and 
memory safety hazard. If a test suite contains a good share of tests to 
exercise how built-ins react when passed proxies as arguments (including 
'this'), this would provide some level of confidence that the 
implementations aren't too memory unsafe.
What the tests exactly returns will of course have to be determine by an 
accurate spec, no doubt here.
I was thinking of tests as a coverage method here, not as a conformance 
tool.




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 introduction of [[invoke]] in this particular context might be an 
instance of may constrain what we can do later. Specifically, it may 
collide and feel duplicate if a more generic solution is found for 
Date.prototype.getMonth.call(proxy); a more useful example of which is 
Set.call(proxy).








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.
How did the discussion shift from 

Re: Proxy-for-array transparency issues

2013-07-30 Thread Allen Wirfs-Brock

On Jul 30, 2013, at 12:40 PM, David Bruant wrote:

 Le 30/07/2013 18:57, Allen Wirfs-Brock a écrit :
 ...
 
 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. 
 Wouldn't replacing the proxy reference for the target reference be violating 
 stratification?

It depends upon the use for the proxy.  There is no stratification if the Proxy 
is being used to implement the a virtual object.  

 Per exotic type traps would solve the issue generically, I think.

It might for ES6 and for this use case.  But it doesn't generalize to user 
defined classes with private state.  It also does solve the problem for 
identity based testing.  EG, using a WeakMap for branding or holding private 
state.  The Proxy object and its target object are not the same map key.

 
 
 Do you have new use cases, that motivate the design of an enhanced 
 Array.isArray?
 I cited membrane transparency a couple of times. Tom seems to agree. Others 
 have opinions?

I was really asking about purpose of application level Array.isArray tests.  
What is the application really asking when it uses that test? Is it really 
asking array-like?  What counts as array-like?

 
 
 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. 
 ...
 If, for instance, you have an areYouAnArray trap that only works if the 
 target is an Array (recursive definition with actual arrays as base case), 
 then Array.isArray isn't spoofable by any object.
 Mark and Tom once used a expression about direct proxies. Something like 
 invariant forwarding or something like that, where the target imposes 
 restrictions on the handler. This could be extended to exotic objects by 
 adding per exotic type only traps.

Let me reinterpret this as as request for a [[GetNomimalType]] trap.  What are 
the set of expected values?  What happens if the handler lies? What could 
somebody do with the result?  

Allen

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


Re: Proxy-for-array transparency issues

2013-07-30 Thread Till Schneidereit
On Tue, Jul 30, 2013 at 10:19 PM, Allen Wirfs-Brock
al...@wirfs-brock.comwrote:

 I was really asking about purpose of application level Array.isArray
 tests.  What is the application really asking when it uses that test? Is it
 really asking array-like?  What counts as array-like?


My guess is: whether the generic Array methods work for this object. Which
is a sensible thing to want to know, and which, imo, Array.isArray *seems*
to provide, if you don't know better.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Proxy-for-array transparency issues

2013-07-30 Thread Allen Wirfs-Brock

On Jul 30, 2013, at 2:21 PM, Till Schneidereit wrote:

 On Tue, Jul 30, 2013 at 10:19 PM, Allen Wirfs-Brock al...@wirfs-brock.com 
 wrote:
 I was really asking about purpose of application level Array.isArray tests.  
 What is the application really asking when it uses that test? Is it really 
 asking array-like?  What counts as array-like?
 
 My guess is: whether the generic Array methods work for this object. Which is 
 a sensible thing to want to know, and which, imo, Array.isArray *seems* to 
 provide, if you don't know better.
 

In which case, we are talking about bogus tests because that isn't really what 
Array.isArray determines and the generic Array methods will work (to some 
degree or another) on any object. 

We could define a new predicate Array.isArrayLike with a proxy friendly 
extensions mechanism (@@isArrayLike).  It wouldn't be the same test as 
Array.isArray and the result would be more a statement of intent than an 
absolute guarantee.

Would anybody use it? Would it's existence be enough to eliminate the 
Array.isArray/proxy concern?

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


Re: Proxy-for-array transparency issues

2013-07-30 Thread David Bruant

Le 30/07/2013 22:19, Allen Wirfs-Brock a écrit :


On Jul 30, 2013, at 12:40 PM, David Bruant wrote:


Le 30/07/2013 18:57, Allen Wirfs-Brock a écrit :

...


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.
Wouldn't replacing the proxy reference for the target reference be 
violating stratification?


It depends upon the use for the proxy.  There is no stratification if 
the Proxy is being used to implement the a virtual object.



Per exotic type traps would solve the issue generically, I think.


It might for ES6 and for this use case.  But it doesn't generalize to 
user defined classes with private state.
Spent 2 hours on this email refining a proposal. It started with the 
idea of per exotic type traps. Then moved to user-defined traps. Then to 
something more generic:


The problem we have is that some function have particular expectations 
on some of their arguments (including 'this') and proxies may violate 
these expectations. What if functions could defend against proxies by 
encouraging them to unwrap? new trap: defensiveFunctionCall


var f = makeDefensiveFunction(a = a.a);
var o = { a : 37 };
f(o); // 37

var p = new Proxy(o, {
defensiveFunctionCall: (target, defensiveFunction, position) = {
return; // means agreement for the target to be passed
// to defensiveFunction as position-th argument
// throw to disagree
}
});

f(p) // calls the defensiveFunctionCall trap.
// the proxy chooses to reveal its target to the function by returning
// the function is called with the target as argument
// 37 is returned

Class syntax could make methods defensive against proxies by default.

class Secretive{
private secret = String(Math.random()).substr(2)

public getPartial(){
return this.secret.substr(0, 3);
}

public changeSecret(){
this.secret = String(Math.random()).substr(2);
}

}

var s = new Secretive();
console.log(s.getPartial()) // 3 digits

var p = new Proxy(s, {
defensiveFunctionCall: (target, defensiveFunction, position) = {
return;
}
});
console.log(p.getPartial()) // get trap, getPartial function is 
returned.

// getPartial is about to be called with the p as 'this' (0th arg)
// because it's defensive, the proxy's defensiveFunctionCall trap 
is called

// return from the trap means agreement
// the getPartial method is called on the actual instance, not the 
proxy

// thus, the secret is never revealed to the proxy

What this takes is for the proxy to reveal its target. This shouldn't be 
a problem for built-ins as they won't leak the target, so they can all 
be defensive against proxies by default, I think (beware of chaining?).
A proxy for a Secretive (user-defined class with private state) has no 
reason to hide its target to a Secretive method if the target is a 
Secretive instance (because the class constructor created the target).



Please note that I have just described a new primitive that allows a 
defense against Sam's attack [1].



I imagine I've been overlooking details, but here is a generic solution 
that enable functions to defend against proxies (unwrapping the proxy), 
while providing a mechanism for proxies to keep their integrity 
(throwing in the trap).
In the case of a function against a proxy, one has to give up something. 
Either the function isn't defensive and lets the proxy visit its guts 
or the proxy lets the function see its guts (the target). But it's not 
possible for both to keep their integrity while the function runs 
against the proxy. And maybe that's a good trade-off?



It also does solve the problem for identity based testing.  EG, using 
a WeakMap for branding or holding private state.  The Proxy object and 
its target object are not the same map key.
Is there any expectation to be able to solve identity-based branding 
with proxies?






Do you have new use cases, that motivate the design of an enhanced 
Array.isArray?
I cited membrane transparency a couple of times. Tom seems to agree. 
Others have opinions?


I was really asking about purpose of application level Array.isArray 
tests.  What is the application really asking when it uses that test? 
Is it really asking array-like?  What counts as array-like?

oh ok, sorry about that.
Then no, I don't think I have a new use case that motivates 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 

Re: Proxy-for-array transparency issues

2013-07-30 Thread Till Schneidereit
On Wed, Jul 31, 2013 at 12:19 AM, Allen Wirfs-Brock
al...@wirfs-brock.comwrote:


 On Jul 30, 2013, at 2:21 PM, Till Schneidereit wrote:

 On Tue, Jul 30, 2013 at 10:19 PM, Allen Wirfs-Brock al...@wirfs-brock.com
  wrote:

 I was really asking about purpose of application level Array.isArray
 tests.  What is the application really asking when it uses that test? Is it
 really asking array-like?  What counts as array-like?


 My guess is: whether the generic Array methods work for this object. Which
 is a sensible thing to want to know, and which, imo, Array.isArray *seems*
 to provide, if you don't know better.


 In which case, we are talking about bogus tests because that isn't really
 what Array.isArray determines and the generic Array methods will work (to
 some degree or another) on any object.


I'm aware. And I don't have evidence for tests like that existing. Maybe
somebody looking to verify that some object fulfills some kind of contract
would know better than naively using isArray without knowing what it
actually does.



 We could define a new predicate Array.isArrayLike with a proxy friendly
 extensions mechanism (@@isArrayLike).  It wouldn't be the same test as
 Array.isArray and the result would be more a statement of intent than an
 absolute guarantee.

 Would anybody use it? Would it's existence be enough to eliminate the
 Array.isArray/proxy concern?


It probably would, if the concern is a valid one at all. Somebody naive
enough to use isArray would probably still stumble over the existence of an
isArrayLike.

It's probably just not worth it, though.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Proxy-for-array transparency issues

2013-07-29 Thread Allen Wirfs-Brock

On Jul 29, 2013, at 9:06 AM, Tom Van Cutsem wrote:

 Hi,
 
 Originally, direct proxies were specified such that a direct proxy would 
 inherit the [[Class]] of the target object it wraps. The intent was for e.g. 
 proxies-for-arrays to be recognized properly as arrays.
 
 In ES6 the [[Class]] property is gone and the current draft instead uses 
 wording such as if O is an exotic Array object...
 
 My understanding is that a proxy for an array would not pass such a test, 
 unless we explicitly state otherwise.

yes that's correct

 
 Allen, could you clarify your intent?

What you are running into is very closely related to vthe private state access 
issues that led us to define DelegatingHandler/ForwardHandler, etc.  The 
difference here is that you are concerned about external behavioral branding 
rather than internal implementation branding of the sort that occurs for 
private state access.

The legacy [[Class]] internal property conflated these two concepts.  Sometimes 
it was used for to ensure that a built-in method was operating upon an instance 
that actually had the internal state or conformed to other implementation level 
invariants needed by the method. Other times, [[Class]] was tested  for basic 
external behavioral classification purposes that don't really care at all about 
implementation level object invariants.

In most cases, the ES6 spec. language such as  if O is an exotic X object or 
does X have a [[XXX]] internal data property works fine as a direct 
replacement of an ES5  [[Class]] test because there are a one-to-one correspond 
between a ES6 built-in that is represented by specific kind of exotic object or 
that has a specific internal data property and with a ES5 built-in with the 
corresponding [[Class]] value. 

However, a proxy on such a built-in does not pass such a test.  A Proxy object 
whose target is an Array is an exotic proxy object, not an exotic array object. 
 It would be unsafe to allow such a proxy to be recognized an an exotic array 
regardless of whether it was done via the ES6 spec. language or via 
[[Class]]==Array  if we still had it.  A proxy for an array and an array is not 
likely to have the same implementation shape.  A method that tests for an 
exotic array object might should be able to assume, for example, that its 
implementation depended encoding of the length property is present.  Disaster 
would follow if the method tried to operate upon a proxy instance instead of an 
actual exotic array instance.

The general solution to this problem is to decouple the shape branding/testing 
from the behavior testing. This is already done a number of places in the ES6 
spec to support subclassing flexibility.

For example, a number of the ES=5 String method such as replace have 
different behavior depending upon whether an argument is a RegExp or a string. 
In the ES6 spec. the [[Class]]==RegExp test is replaced by an HasProperty test 
for @@isRegExp and and a form of double dispatching.  This permits subclasses 
of RegExp (or even alternative regular expression engines that don't inherit 
from the built-in RegExp) to be used in that argument position.  It may also be 
transparent to proxying (depending upon the handler). 

In general, an case by case analysis needs to be done for each of the 
situations where [[Class]] is used in ES5 for behavioral checking to se if and 
how an alternative needs to be provided for ES6.

 
 If proxies for arrays do not pass such tests, some built-ins behave in 
 unexpected ways. 

What's expected?  Just because a proxy has an exotic array object as its target 
doesn't mean that is functions as an exotic array.


 
 Here's the list of relevant built-ins, based on searching the ES6 spec for 
 is an exotic Array object:
 * Object.prototype.toString

As currently spec'ed. toString will invoke the HasProperty(@@toStringTag) of 
the proxy and if the result is true invoke the Get trap to retrieve the value 
used to construct the toString result. All of the new built-ins have 
@@toStringTag methods.  I considered adding them for the built--ins that carry 
over from ES5.  Then, if the @@toStringTag of Array.prototype is Array then 
Object.prototype.toString(new Proxy([ ], { })) should return [Object Array].  
However, this would be a breaking change for existing code explicitly wires 
their prototype chain to inherit from Array.prototype.  


 * Array.isArray

We've discussed the meaning of this in the past and have agreed that it should 
be considered a test for exotic array-ness and in particular the length 
invariant. A Proxy whose target is an exotic array may or may not qualify. We 
could add a @@isArray tag, but I'm not convinced that it is really needed.   

 * Array.prototype.concat

As currently spec'ed the [[Class]] test has been replaced with an exotic array 
test on the this value (supporting creating subclass instances) and a 
IsConcatSpreadable abstract operation (defined in terms of 
@@isConcatSpreadable) falling back to 

Re: Proxy-for-array transparency issues

2013-07-29 Thread David Bruant

Le 29/07/2013 20:41, Allen Wirfs-Brock a écrit :

The legacy [[Class]] internal property conflated these two concepts.  Sometimes 
it was used for to ensure that a built-in method was operating upon an instance 
that actually had the internal state or conformed to other implementation level 
invariants needed by the method. Other times, [[Class]] was tested  for basic 
external behavioral classification purposes that don't really care at all about 
implementation level object invariants.

In most cases, the ES6 spec. language such as  if O is an exotic X object or does 
X have a [[XXX]] internal data property works fine as a direct replacement of an ES5  
[[Class]] test because there are a one-to-one correspond between a ES6 built-in that is represented 
by specific kind of exotic object or that has a specific internal data property and with a ES5 
built-in with the corresponding [[Class]] value.
Can all the [[Class]] replacement tests be passed by proxies in a way or 
another so that a proxy can impersonate a given class of exotic 
object? (most likely by having one of these objects as target)


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



If proxies for arrays do not pass such tests, some built-ins behave in 
unexpected ways.

What's expected?  Just because a proxy has an exotic array object as its target 
doesn't mean that is functions as an exotic array.
This suggests that the opposite could be true, that is that a proxy with 
any target might impersonates an array as long as it passes some tests. 
I wonder how much of a good idea this is.


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



Here's the list of relevant built-ins, based on searching the ES6 spec for is an 
exotic Array object:
* Object.prototype.toString

As currently spec'ed. toString will invoke the HasProperty(@@toStringTag) of the proxy and if the 
result is true invoke the Get trap to retrieve the value used to construct the toString result. All 
of the new built-ins have @@toStringTag methods.  I considered adding them for the built--ins that 
carry over from ES5.  Then, if the @@toStringTag of Array.prototype is Array then 
Object.prototype.toString(new Proxy([ ], { })) should return [Object Array].

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



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

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


* Array.isArray

We've discussed the meaning of this in the past and have agreed that it should 
be considered a test for exotic array-ness and in particular the length 
invariant. A Proxy whose target is an exotic array may or may not qualify.
I don't really understand what you're testing here to checking the 
length invariant.

Can a proxy be written to pass this test?
Can a proxy be written so that the value of this test changes over time?


* JSON.stringify

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



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

They may expect this, but I don't see what generalizations we can make.  
Whether a proxy over a built-in is behaviorally substitutable for the built-in 
completely dependent upon the the definition of the specific proxy.
Again, this seems to suggest that a proxy could pretend to be a Date to 
one algorithm, an Array to another and a RegExp to another. I'm not sure 
what good comes out of that.


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


Re: Proxy-for-array transparency issues

2013-07-29 Thread Brendan Eich

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


+1

What have we gained?

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


Re: Proxy-for-array transparency issues

2013-07-29 Thread Brandon Benvie

On 7/29/2013 5:14 PM, Brendan Eich wrote:

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


+1

What have we gained?


It seems to me like duck-typing based on internal properties was 
basically superseded by @@create and this change could be rolled back.

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


Re: Proxy-for-array transparency issues

2013-07-29 Thread Allen Wirfs-Brock

On Jul 29, 2013, at 5:11 PM, David Bruant wrote:

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

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.

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

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.

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

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 ES6 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 

Re: Proxy-for-array transparency issues

2013-07-29 Thread David Bruant

Le 30/07/2013 03:09, Allen Wirfs-Brock a écrit :

On Jul 29, 2013, at 5:11 PM, David Bruant wrote:


Le 29/07/2013 20:41, Allen Wirfs-Brock a écrit :

The legacy [[Class]] internal property conflated these two concepts.  Sometimes 
it was used for to ensure that a built-in method was operating upon an instance 
that actually had the internal state or conformed to other implementation level 
invariants needed by the method. Other times, [[Class]] was tested  for basic 
external behavioral classification purposes that don't really care at all about 
implementation level object invariants.

In most cases, the ES6 spec. language such as  if O is an exotic X object or does 
X have a [[XXX]] internal data property works fine as a direct replacement of an ES5  
[[Class]] test because there are a one-to-one correspond between a ES6 built-in that is represented 
by specific kind of exotic object or that has a specific internal data property and with a ES5 
built-in with the corresponding [[Class]] value.

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

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)
By this object reference, are you talking about the this keyword? 
Even then, I wouldn't be sure to understand. Which part of ES5.1 are you 
referring to?

I believe a code snippet to explain would make things easier to understand.


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.


If proxies for arrays do not pass such tests, some built-ins behave in 
unexpected ways.

What's expected?  Just because a proxy has an exotic array object as its target 
doesn't mean that is functions as an exotic array.

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

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.
Self-hosted code is privileged and may have some power not described by 
the ES spec (and as far as I know, that's actually the case both for 
SpiderMonkey and V8 self-hosted code). 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.



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.
Note that the design of proxies (can only be new objects, are limited to 
an immutable {target, handler} data structure, stratified API, etc.) go 
a long way in preventing memory safety issues. It sounds reasonable to 
think that implementors will do the necessary rest of work to prevent 
these issues in already implemented algorithms.
Actually, if the stratification is respected and there is no free 
bypass, there is no reason to 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.

I don't think you're answering my point.
All tests that 

Re: Proxy questions

2013-01-21 Thread Kevin Smith
 I want to stress this again: proxies, for all operations they can
 intercept, can always decide to go into an infinite loop or throw.
 If they do throw, they can't hide their attack from your code. In that
 sense they don't violate the code's integrity. The invariant enforcement
 mechanism is based on the same assumptions: if the proxy detects that the
 handler behaves badly, throw to signal the problem.

 The alternative to throwing would be for proxies to absorb any exceptions
 thrown by traps, but that would be worse (silent failures).


Sure.

Quoting you from the other thread:


 Indeed. But in Javascript, methods shouldn't (in general) make any
 assumptions about their |this| values.


OK - but we can't have it both ways.  We can't allow |this| to give us
access to private data (regardless of the implementation) *and also*
allow that |this| may be an untrusted proxy.  If |this| grants access to
private data, then it must be trustable.  Anything else is inherently risky.

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


Re: Proxy questions

2013-01-21 Thread Brendan Eich

Kevin Smith wrote:
OK - but we can't have it both ways.  We can't allow |this| to give us 
access to private data (regardless of the implementation) *and also* 
allow that |this| may be an untrusted proxy.  If |this| grants access 
to private data, then it must be trustable.  Anything else is 
inherently risky.


Who said otherwise?

First, as Tom noted, |this| binding in JS is dynamic unless you opt out.

Second, private symbols need not leak. We have had several designs to 
avoid leakage, and Tom' s advocating another that could work.


I know, you want to get rid of (defer, let's say) private symbols. But 
no one is trying to have it both ways. Everyone wants to avoid private 
symbol leaks via proxies, in the face of dynamic |this| and other 
hazards of JS not related to |this|.


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


Re: Proxy questions

2013-01-20 Thread Kevin Smith
 Does the stack unwind as with normal error handling?  Does after bar get
 logged?  (FF18 answers yes to the first and no to the second question.)

 I agree with FF18 here.


OK.  Consider this:

class Purse {

private balance;

constructor() {
balance = 0;
Object.freeze(this);
}

getBalance() { return balance; }

somethingInocuous() {}

deposit(amount, srcPurse) {
private(srcPurse).balance -= amount;
this.somethingInocuous();
balance += amount;
}
}

A proxy for a Purse instance could throw on access to somethingInocuous,
leaving the high-integrity object in an inconsistent state.  It would seem
that a high-integrity object would need to assume that any access to a
public property might throw, in case the object is being proxied.

Am I thinking about this correctly?

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


Re: Proxy questions

2013-01-20 Thread Mark S. Miller
Before commenting on the general question, I'm confused about
something in your code. How did a proxy get bound to this in your
example?

On Sun, Jan 20, 2013 at 10:49 AM, Kevin Smith khs4...@gmail.com wrote:

 Does the stack unwind as with normal error handling?  Does after bar
 get logged?  (FF18 answers yes to the first and no to the second question.)

 I agree with FF18 here.


 OK.  Consider this:

 class Purse {

 private balance;

 constructor() {
 balance = 0;
 Object.freeze(this);
 }

 getBalance() { return balance; }

 somethingInocuous() {}

 deposit(amount, srcPurse) {
 private(srcPurse).balance -= amount;
 this.somethingInocuous();
 balance += amount;
 }
 }

 A proxy for a Purse instance could throw on access to somethingInocuous,
 leaving the high-integrity object in an inconsistent state.  It would seem
 that a high-integrity object would need to assume that any access to a
 public property might throw, in case the object is being proxied.

 Am I thinking about this correctly?

 { Kevin }

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




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


Re: Proxy questions

2013-01-20 Thread Kevin Smith
Let me correct a typo in that last one:

var blackHolePurse = new Purse();

var blackHole = new Proxy(blackHolePurse, {

get: function(obj, name) {

if (name === somethingInocuous) throw new Error(Up in
smoke!);
return obj[name];
}
});

try { blackHole.deposit(1000, myPurse); }
catch (x) { /* Oops - $1000 just disappeared from existence. */ }

Again - more foolish than evil.  : )

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


Re: Proxy target as __proto__? (Re: Proxy's optional target)

2013-01-19 Thread Tom Van Cutsem
2013/1/18 Claus Reinke claus.rei...@talk21.com

 PS. I probably shouldn't mention that Proxies' invariant checks
only against own properties behave differently from how non
Proxy objects behave, if a target prototype property happensto be
 frozen (override prohibition non-mistake)?

 var x = Object.freeze({foo: 88});
 var y = Object.create(x);

 y.foo = 99; // fail
 console.log( y.foo ); // 88

 var yp = Proxy(y,{get:function(t,n,r){ return n===foo ? 99 : t[n] } });
 console.log( yp.foo ); // 99


Yep, this is true. But it doesn't violate any invariants since we could
have made y.foo return 99 as well, if we had used Object.defineProperty to
shadow 'foo'.

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


Re: Proxy target as __proto__? (Re: Proxy's optional target)

2013-01-18 Thread Tom Van Cutsem
Hi Claus,

I'm not sure I fully understand your proposal, but could you not achieve it
by simply doing:

var target = ...; // might be frozen
var p = Proxy( Object.create(target), handler);

?

Cheers,
Tom

2013/1/17 Claus Reinke claus.rei...@talk21.com

 The proxy target is important because it specifies some invariants about
 the proxy (typeof, builtin brand, behavior of forwarding for unspecified
 traps, values of internal properties like [[DateValue]], [[NumberValue]],
 etc.).


 That is probably the most important difference between direct
 proxies and old-style proxies. Yet I find it slightly limiting and
 accident-prone: it uses invariants and target to make proxies
 not just behave like an object, but to behave like the target.

 Presentations on direct proxies tend to present too usage patterns:
 wrapped objects and virtual objects.

 My problem is: if I am using proxies as wrappers, I want to use
 the target object as a -wait for it- prototype, to be *modified* by
 the proxy. But if the target object happens to be frozen, modified returns
 are no longer allowed by the invariants. To cover this
 eventuality, I should use the virtual object pattern even if I
 just want to wrap an object!

 Would it be possible/helpful to use the target merely as a __proto__
 instead of a harness, inheriting the target's internal properties without
 over-constraining the proxy's ability to
 modify the wrapped target's behavior? Invariants could still use an
 implied object for freezing the *proxy*, so the proxy would behave as an
 object, not necessarily the same as the target object.

 Claus

 __**_
 es-discuss mailing list
 es-discuss@mozilla.org
 https://mail.mozilla.org/**listinfo/es-discusshttps://mail.mozilla.org/listinfo/es-discuss

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


Re: Proxy target as __proto__? (Re: Proxy's optional target)

2013-01-18 Thread Claus Reinke

Hi Tom,


I'm not sure I fully understand your proposal, but could you not achieve it
by simply doing:

var target = ...; // might be frozen
var p = Proxy( Object.create(target), handler);


Ah, too obvious for me, thanks! 

Also, proxy wrappers often modify functions, which tend to be on 
a non-frozen prototype. So perhaps it isn't as big an issue as I thought.


Claus

PS. I probably shouldn't mention that Proxies' invariant checks
   only against own properties behave differently from how non
   Proxy objects behave, if a target prototype property happens 
   to be frozen (override prohibition non-mistake)?


var x = Object.freeze({foo: 88});
var y = Object.create(x);

y.foo = 99; // fail
console.log( y.foo ); // 88

var yp = Proxy(y,{get:function(t,n,r){ return n===foo ? 99 : t[n] } });
console.log( yp.foo ); // 99

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


Re: Proxy-induced impurity of internal methods

2011-10-19 Thread Tom Van Cutsem
2011/10/6 Andreas Rossberg rossb...@google.com

 A related nit: even for freeze and friends, the restriction on
 recursive fix is NOT enough as currently stated in the proxy
 semantics. Consider:

 --
 var handler = {
  get fix() { Object.seal(p); return {} }
 }
 var p = Proxy.create(handler)
 Object.freeze(p)
 --

 Strictly speaking, there actually is no recursive execution of fix()
 -- the recursion occurs a few steps earlies, when we try to _get_ the
 fix function. Firefox rejects this nevertheless:

 TypeError on line 2: proxy was fixed while executing the handler

 V8 bails out with a stack overflow:

 RangeError: Maximum call stack size exceeded

 While this might merely be a nit, it shows that it is _not_ generally
 enough to only prevent fixing while _executing_ traps. To be
 conservative, it seems like we perhaps have to disallow any reentrant
 use of freeze/seal/prevenExt at any point in _any_ internal method of
 the same object. But how spec that?


I've been re-examining this issue for direct proxies. My conclusion is that
for direct proxies, in principle, stopTrapping can safely be invoked while
executing any trap. The reason why this works is primarily because direct
proxies, as currently proposed, no longer need default implementations for
missing derived traps.

The first thing an intercepted operation does is to [[Get]] the trap from
the handler, and to [[Call]] it if it exists. Once the trap is [[Call]]-ed,
the handler is never referenced anymore. So, if a proxy becomes non-trapping
with active trap invocations still on the stack, those trap invocations,
when they resume, will never reference the handler anymore, so are not
critically affected by the fact that the proxy is now fixed and the
handler is nulled out.

The above example (trying to fix a proxy while fixing it) would then go into
an infinite loop, which is perfectly reasonable from a semantic point of
view. It's no different from a handler trying to implement
getOwnPropertyDescriptor by calling getOwnPropertyDescriptor on the proxy
itself.

Whether or not we should re-check the state of a proxy after [[Get]]-ting a
trap implemented as an accessor remains unclear. For direct proxies, either
option is safe, but we have to make a choice since the difference is
observable, cf. 
http://code.google.com/p/es-lab/source/browse/trunk/src/proxies/DirectProxies.js#363


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


Re: Proxy-induced impurity of internal methods

2011-10-10 Thread Tom Van Cutsem
Hi Andreas,

These are all good points. Some comments below:

2011/10/5 Andreas Rossberg rossb...@google.com

 Proxies invalidate one fundamental assumption of the current ES spec,
 namely that (most) internal methods are effectively pure. That has a
 couple of consequences which the current proxy proposal and semantics
 seem to ignore, but which we need to address.


 OBSERVABILITY  EFFICIENCY

 In ES5, internal methods essentially are an implementation detail of
 the spec. AFAICS, there is no way their interaction is actually
 observable in user code. This gives JS implementations significant
 leeway in implementing objects (and they make use of it).

 This changes drastically with proxies. In particular, since most
 internal methods may now invoke traps directly or indirectly, we can
 suddenly observe many internal steps of property lookup and similar
 operations through potential side effects of these traps. (Previously,
 only the invocation of getters or setters was observable).


 Take the following simple example:

 
 var desc = {configurable: true, get: function() {return 8}, set:
 function() {return true}}
 var handler = {getPropertyDescriptor: function() {seq += G; return desc}}
 var p = Proxy.create(handler)
 var o = Object.create(p)

 var seq = 
 o.x
 var seq1 = seq
 seq = 
 o.x = 0
 var seq2 = seq
 

 According to the proxy spec, we should see seq1==G and seq2==GG.
 In my local version of V8, I currently see seq1==G and seq2==G.
 In Firefox 7, I see seq1==GG and seq2==GG.


This point was previously noted, see: 
http://wiki.ecmascript.org/doku.php?id=strawman:proxy_set_trap
It was brought up at the March 2011 meeting, and IIRC we were in agreement
that the spec. should be adapted to remove the redundant
getPropertyDescriptor call.


 Obviously, both implementations are unfaithful to the spec, albeit in
 reverse ways. At least for V8, implementing the correct behaviour may
 require significant changes.

 Also, I wonder whether the current semantics forcing seq2==GG really
 is what we want, given that it is unnecessarily inefficient (note that
 it also involves converting the property descriptor twice, which in
 turn can spawn numerous calls into user code). Optimizing this would
 require purity analysis on trap functions, which seems difficult in
 general.


I agree. This is clearly a case where the ES5 spec was written assuming this
was all unobservable.


 HIDDEN ASSUMPTIONS

 In a number of places, the ES5 spec makes hidden assumptions about the
 purity of internal method calls, and derives certain invariants from
 that, which break with proxies.

 For example, in the spec of [[Put]] (8.12.5), step 5.a asserts that
 desc.[[Set]] cannot be undefined. That is true in ES5, but no longer
 with proxies. Unsurprisingly, both Firefox and V8 do funny things for
 the following example:

 
 var handler = {
  getPropertyDescriptor: function() {
Object.defineProperty(o, x, {get: function() { return 5 }})
return {set: function() {}}
  }
 }
 var p = Proxy.create(handler)
 var o = Object.create(p)
 o.x = 4
 

 Firefox 7: InternalError on line 1: too much recursion
 V8: TypeError: Trap #error of proxy handler #Object returned
 non-configurable descriptor for property x


(are you sure this tests the right behavior? It seems the V8 TypeError is
simply due to the fact that the descriptor returned from
getPropertyDescriptor is configurable.)

More generally, there is no guarantee anymore that the result of
 [[CanPut]] in step 1 of [[Put]] is in any way consistent with what we
 see in later steps. In this light (and due to the efficiency reasons I
 mentioned earlier), we might want to consider rethinking the
 CanPut/Put split.


I agree. In fact, proxies already abandon the CanPut/Put split: they
implement CanPut simply by always returning true, and perform all of their
assignment logic in [[Put]]. Related to this refactoring: Mark has
previously proposed introducing a [[Set]] trap that simply returns a
boolean, indicating whether or not the assignment succeeded. The [[Put]]
trap would simply call [[Set]], converting a false result into a TypeError
when appropriate (cf. 
http://wiki.ecmascript.org/doku.php?id=harmony:proxy_defaulthandler#alternative_implementation_for_default_set_trap).
We don't have consensus on this yet. I would propose to discuss the
CanPut/Put refactoring and the [[Set]] alternative together during the Nov.
meeting.


 This is just one case. There may be other problematic places in other
 operations. Most of them are probably more subtle, i.e. the spec still
 prescribes some behaviour, but that does not necessarily make any
 sense for certain cases (and would be hard to implement to the
 letter). We probably need to check the whole spec very carefully.


 FIXING PROXIES

 A particularly worrisome side effect is fixing a proxy. The proxy
 semantics contains a lot of places saying If O is a trapping proxy,
 do steps I-J. 

Re: Proxy-induced impurity of internal methods

2011-10-10 Thread Tom Van Cutsem
2011/10/6 Andreas Rossberg rossb...@google.com

 A related nit: even for freeze and friends, the restriction on
 recursive fix is NOT enough as currently stated in the proxy
 semantics. Consider:

 --
 var handler = {
  get fix() { Object.seal(p); return {} }
 }
 var p = Proxy.create(handler)
 Object.freeze(p)
 --

 Strictly speaking, there actually is no recursive execution of fix()
 -- the recursion occurs a few steps earlies, when we try to _get_ the
 fix function. Firefox rejects this nevertheless:

 TypeError on line 2: proxy was fixed while executing the handler

 V8 bails out with a stack overflow:

 RangeError: Maximum call stack size exceeded

 While this might merely be a nit, it shows that it is _not_ generally
 enough to only prevent fixing while _executing_ traps. To be
 conservative, it seems like we perhaps have to disallow any reentrant
 use of freeze/seal/prevenExt at any point in _any_ internal method of
 the same object. But how spec that?


In my FixedHandler code, I used the following trick to disallow recursive
fixing:

// this fix function is a wrapper around the 'real' fix function:
  fix: function(operation) {
if (this.fixing) {
  throw new TypeError(cannot recursively call the fix() trap while
fixing a proxy);
}
var props = null;
try {
  this.fixing = true;
  props = this.targetHandler.fix(operation);
} finally {
  delete this.fixing;
}

// process props ...
  },

I guess Firefox does something similar in spirit. Since the flag is set
before the lookup of this.targetHandler.fix, that explains why even during
the lookup of fix, the proxy can't fix recursively. Generalizing the flag
to account for all traps is going to be tricky and expensive, though, which
suggests that this may not be the right behavior.

I will go over the proposed proxies spec to check whether there is actually
any harm in allowing a proxy to become non-trapping during an active trap.
If the proxy describes a coherent object before and after the state change,
there is no reason to disallow this. The new proposal Mark and I have been
working on may help here, since it enforces more invariants on proxies.

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


Re: Proxy-induced impurity of internal methods

2011-10-10 Thread Andreas Rossberg
On 10 October 2011 15:38, Tom Van Cutsem tomvc...@gmail.com wrote:
 This point was previously noted, see:
 http://wiki.ecmascript.org/doku.php?id=strawman:proxy_set_trap
 It was brought up at the March 2011 meeting, and IIRC we were in agreement
 that the spec. should be adapted to remove the redundant
 getPropertyDescriptor call.

Ah, thanks. I wasn't aware of that. Good to hear.

 In a number of places, the ES5 spec makes hidden assumptions about the
 purity of internal method calls, and derives certain invariants from
 that, which break with proxies.

 For example, in the spec of [[Put]] (8.12.5), step 5.a asserts that
 desc.[[Set]] cannot be undefined. That is true in ES5, but no longer
 with proxies. Unsurprisingly, both Firefox and V8 do funny things for
 the following example:

 
 var handler = {
  getPropertyDescriptor: function() {
    Object.defineProperty(o, x, {get: function() { return 5 }})
    return {set: function() {}}
  }
 }
 var p = Proxy.create(handler)
 var o = Object.create(p)
 o.x = 4
 

 Firefox 7: InternalError on line 1: too much recursion
 V8: TypeError: Trap #error of proxy handler #Object returned
 non-configurable descriptor for property x

 (are you sure this tests the right behavior? It seems the V8 TypeError is
 simply due to the fact that the descriptor returned from
 getPropertyDescriptor is configurable.)

You are right, of course. If I make it configurable, V8 returns
without error. However, by modifying the example somewhat you can see
that it executes the setter from the descriptor then. That is not
quite right either (Though neither wrong, I suppose :) ).

 I agree. In fact, proxies already abandon the CanPut/Put split: they
 implement CanPut simply by always returning true, and perform all of their
 assignment logic in [[Put]]. Related to this refactoring: Mark has
 previously proposed introducing a [[Set]] trap that simply returns a
 boolean, indicating whether or not the assignment succeeded. The [[Put]]
 trap would simply call [[Set]], converting a false result into a TypeError
 when appropriate (cf.
 http://wiki.ecmascript.org/doku.php?id=harmony:proxy_defaulthandler#alternative_implementation_for_default_set_trap).
 We don't have consensus on this yet. I would propose to discuss the
 CanPut/Put refactoring and the [[Set]] alternative together during the Nov.
 meeting.

Yes, that makes sense.

On 10 October 2011 16:01, Tom Van Cutsem tomvc...@gmail.com wrote:
 I will go over the proposed proxies spec to check whether there is actually
 any harm in allowing a proxy to become non-trapping during an active trap.
 If the proxy describes a coherent object before and after the state change,
 there is no reason to disallow this. The new proposal Mark and I have been
 working on may help here, since it enforces more invariants on proxies.

I'm not sure I understand what you mean by becoming non-trapping,
can you elaborate? What would it do instead?

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


Re: Proxy-induced impurity of internal methods

2011-10-10 Thread Tom Van Cutsem
2011/10/10 Andreas Rossberg rossb...@google.com

 On 10 October 2011 16:01, Tom Van Cutsem tomvc...@gmail.com wrote:
  I will go over the proposed proxies spec to check whether there is
 actually
  any harm in allowing a proxy to become non-trapping during an active
 trap.
  If the proxy describes a coherent object before and after the state
 change,
  there is no reason to disallow this. The new proposal Mark and I have
 been
  working on may help here, since it enforces more invariants on proxies.

 I'm not sure I understand what you mean by becoming non-trapping,
 can you elaborate? What would it do instead?


By becoming non-trapping, I simply meant fixing the proxy (i.e. the state
where the proxy no longer traps the handler, but instead becomes a normal
Object).

In the proposal we are writing up, we would split up the old fix trap in two
different traps:
- Object.{freeze,seal,preventExtensions}(p) would trigger p's protect
trap. That trap would effectively make the proxy
frozen/sealed/non-extensible. A frozen/sealed/non-extensible proxy can still
be trapping.
- A separate Proxy.stopTrapping(p) function would trigger p's stopTrapping
trap. If that trap does not reject the request, the proxy handler would be
switched off, effectively turning the proxy into a regular object. This
corresponds to the become behavior of the current fix() trap.

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


Re: Proxy-induced impurity of internal methods

2011-10-06 Thread Andreas Rossberg
On 6 October 2011 06:34, Allen Wirfs-Brock al...@wirfs-brock.com wrote:
 On Oct 5, 2011, at 9:57 AM, Andreas Rossberg wrote:
 In summary, I'm slightly worried. The above all seems fixable, but is
 that all? Ideally, I'd like to see a more thorough analysis of how the
 addition of proxies affects properties of the language and its spec.
 But given the state of the ES spec, that is probably too much to wish
 for... :)

 I'm not sure what you mean my the last sentence. I have not yet done any
 work to incorporate proxies into the ES6 draft.

Oh, sorry, my remark was unintentionally ambiguous -- it wasn't
directed at you. Just the generic rant that the whole ES spec is a
horribly ad-hoc, utterly unanalysable beast using the state-of-the-art
of language specification from 1960. :)  Clearly nothing the editor
could or should just fix at this point.

 If you have specific issues like these a good way to capture them is to file
 bugs against  the proposals component  of the harmony products at
 bugs.ecmascript.org.  Proposes resolutions would be good too.  I definitely
 look at reported proposal bugs when I work on incorporating new features
 into the draft specification.  On the other hand I don't guarantee that I
 will spot or remember all issues raised on this list.  So file bugs.

Fair enough. This time, however, my comments were mainly meant for Tom
 Mark, who are working on the proposal right now I think. I refrained
from suggesting concrete fixes because they probably have a better
idea what semantics they envision.

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


Re: Proxy-induced impurity of internal methods

2011-10-06 Thread Andreas Rossberg
On 5 October 2011 21:00, Andreas Rossberg rossb...@google.com wrote:
 On 5 October 2011 18:57, Andreas Rossberg rossb...@google.com wrote:
 FIXING PROXIES

 A particularly worrisome side effect is fixing a proxy. The proxy
 semantics contains a lot of places saying If O is a trapping proxy,
 do steps I-J. However, there generally is no guarantee that O remains
 a trapping proxy through all of I-J!

 Again, an example:

 
 var handler = {
  get set() { Object.freeze(p); return undefined },
  fix: function() { return {} }
 }
 var p = Proxy.create(handler)
 p.x
 

 Firefox 7: TypeError on line 1: getPropertyDescriptor is not a function
 V8: TypeError: Object #Object has no method 'getPropertyDescriptor'

 Whoops, sorry, I just saw that I screwed up that example. That
 behaviour is perfectly fine, of course. Don't have my notes here, I'll
 deliver the proper example tomorrow.

Here we go (the last line should have been an assignment):


var handler = {
  get set() { Object.freeze(p); return undefined },
  fix: function() { return {} }
}
var p = Proxy.create(handler)
p.x = 4


Firefox 7: TypeError on line 1: proxy was fixed while executing the handler
V8: TypeError: Object #Object has no method 'getOwnPropertyDescriptor'

So Firefox rejects this (consistently with its treatment of other
methods), while V8 tries to go on with the DefaultPut, using the traps
from the handler that it still happens to have around. This is not
quite what the rules of DefaultPut imply, but what the (inconsistent)
note says.

A related nit: even for freeze and friends, the restriction on
recursive fix is NOT enough as currently stated in the proxy
semantics. Consider:

--
var handler = {
  get fix() { Object.seal(p); return {} }
}
var p = Proxy.create(handler)
Object.freeze(p)
--

Strictly speaking, there actually is no recursive execution of fix()
-- the recursion occurs a few steps earlies, when we try to _get_ the
fix function. Firefox rejects this nevertheless:

TypeError on line 2: proxy was fixed while executing the handler

V8 bails out with a stack overflow:

RangeError: Maximum call stack size exceeded

While this might merely be a nit, it shows that it is _not_ generally
enough to only prevent fixing while _executing_ traps. To be
conservative, it seems like we perhaps have to disallow any reentrant
use of freeze/seal/prevenExt at any point in _any_ internal method of
the same object. But how spec that?

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


Re: Proxy-induced impurity of internal methods

2011-10-05 Thread Waldemar Horwat

Please keep bringing these up; they're important.

This is something that we'll need to get nailed down for the spec.  Yes, I'm 
worried too, as this problem is not well-understood.  It has the feel of a 
research problem.

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


Re: Proxy-induced impurity of internal methods

2011-10-05 Thread Andreas Rossberg
On 5 October 2011 18:57, Andreas Rossberg rossb...@google.com wrote:
 FIXING PROXIES

 A particularly worrisome side effect is fixing a proxy. The proxy
 semantics contains a lot of places saying If O is a trapping proxy,
 do steps I-J. However, there generally is no guarantee that O remains
 a trapping proxy through all of I-J!

 Again, an example:

 
 var handler = {
  get set() { Object.freeze(p); return undefined },
  fix: function() { return {} }
 }
 var p = Proxy.create(handler)
 p.x
 

 Firefox 7: TypeError on line 1: getPropertyDescriptor is not a function
 V8: TypeError: Object #Object has no method 'getPropertyDescriptor'

Whoops, sorry, I just saw that I screwed up that example. That
behaviour is perfectly fine, of course. Don't have my notes here, I'll
deliver the proper example tomorrow.

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


Re: Proxy-induced impurity of internal methods

2011-10-05 Thread Allen Wirfs-Brock
Good points that we will have to specify careful.  Also one the reasons we do 
prototype implementations.

Such issues seems inherent in the adoption of an intercession API and 
semantics.  Having to deal with such issues isn't really new.  In ES5 we had to 
deal with this possibility WRT [[Get]] and [[Set]] triggering accessors it 
forced us in some cases to use [[DefineOwnProperty]] instead of [[Put]].  The 
impact on the internal methods were relatively small in ES5.  It was larger for 
some of the syntactic production evaluation semantics. The biggest impact was 
on built-ins. I agree that Proxies will have even broader impact and I can even 
imagine that working through them might lead to some refactoring of the 
internal properties in order to reduce such effects.  such refactorings might 
then force some changes in to the Proxy Traps.

more below

On Oct 5, 2011, at 9:57 AM, Andreas Rossberg wrote:

 
 In summary, I'm slightly worried. The above all seems fixable, but is
 that all? Ideally, I'd like to see a more thorough analysis of how the
 addition of proxies affects properties of the language and its spec.
 But given the state of the ES spec, that is probably too much to wish
 for... :)

I'm not sure what you mean my the last sentence. I have not yet done any work 
to incorporate proxies into the ES6 draft.  What we currently have is proposal 
that does not address this depth of specification.  I can assure you that, we 
will when they start to move into the ES6 draft.

If you have specific issues like these a good way to capture them is to file 
bugs against  the proposals component  of the harmony products at 
bugs.ecmascript.org.  Proposes resolutions would be good too.  I definitely 
look at reported proposal bugs when I work on incorporating new features into 
the draft specification.  On the other hand I don't guarantee that I will spot 
or remember all issues raised on this list.  So file bugs.

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


Re: Proxy semantics and Object.defineProperty

2011-07-13 Thread Tom Van Cutsem
Good catch. It was not intentional to specify that normalized descriptors
are necessarily complete. Actually, there are two cases to consider:
- for defineProperty, the descriptor should not be completed, for exactly
the reason you show.
- for get{Own}PropertyDescriptor, in ES5 the result is always a complete
descriptor, so it is not unreasonable for proxies to auto-complete any
returned descriptor object.

That would indicate that defineProperty needs:

NormalizePropertyDescriptor ( Attributes )
...
2. Let desc be the result of calling ToPropertyDescriptor(Attributes)
3. Let descObj be the result of calling FromGenericPropertyDescriptor(desc)
...

And we need a separate NormalizeAndCompletePropertyDescriptor (invoked by
get{Own}PropertyDescriptor), which is similar to the above, but instead
calls:

NormalizeAndCompletePropertyDescriptor ( Attributes )
...
2. Let desc be the result of calling
ToCompletePropertyDescriptor(Attributes)
3. Let descObj be the result of calling FromPropertyDescriptor(desc)
...

Did I miss anything?

2011/7/13 Jason Orendorff jason.orendo...@gmail.com

 On the wiki page for Proxy semantics,
  http://wiki.ecmascript.org/doku.php?id=harmony:proxies_semantics
 Object.defineProperty is specified to call
 NormalizePropertyDescriptor, which fills in all missing fields of the
 property descriptor.

 This normalization makes it impossible to implement wrappers that are
 transparent to Object.defineProperty. I think it's a bug in the spec.

 For example:

 var obj = {x: 1};
 var wrapper = Proxy.create({
defineProperty: function (name, desc) {
Object.defineProperty(obj, name, desc);
}
 });

 // At this point obj.x is a configurable, writable data property.

 // Now if we do this:
 Object.defineProperty(obj, x, {value: 2});
 // then obj.x is still configurable and writable afterwards.

 // But if we do this:
 Object.defineProperty(wrapper, x, {value: 3});
 // then obj.x becomes non-configurable and non-writable,
 // because the proxy handler received the normalized
 // descriptor {configurable: false, enumerable: false,
 // writable: false, value: 3}.

 -j
 ___
 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: Proxy semantics and Object.defineProperty

2011-07-13 Thread Jason Orendorff
On Wed, Jul 13, 2011 at 10:55 AM, Tom Van Cutsem tomvc...@gmail.com wrote:
 Good catch. It was not intentional to specify that normalized descriptors
 are necessarily complete. Actually, there are two cases to consider:
 - for defineProperty, the descriptor should not be completed, for exactly
 the reason you show.
 - for get{Own}PropertyDescriptor, in ES5 the result is always a complete
 descriptor, so it is not unreasonable for proxies to auto-complete any
 returned descriptor object.

Right, I agree. Thanks for the quick reply.

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


Re: Proxy forwarding handlers and accessor properties

2011-06-19 Thread Tom Van Cutsem
I agree with all of David's points. I wonder though: would it make more
sense if we'd spec. the get trap of Proxy.Handler as:

  get: function(name, proxy) {
let val = this.target[name];
return typeof val === function ? val.bind(this.target) : val;
  }

Then both method  accessor invocation bind |this| to the target.

It's hard to say what the expected default behavior is for the default
forwarding handler: should it leave |this| bound to the proxy or to the
target when forwarding a method invocation? As David mentioned, programmers
can always implement either, but what should be the default? Creating a new
bound function per |get| invocation may be expensive though. Also, treating
a property bound to a function as a method is an imperfect heuristic.

Cheers,
Tom

2011/6/17 David Bruant david.bru...@labri.fr

 Le 17/06/2011 08:42, David Flanagan a écrit :

  On 6/16/11 5:20 PM, David Bruant wrote:

 Le 17/06/2011 01:54, David Flanagan a écrit :


 // When we create a proxy with a forwarding handler, though, the this
 value
 // is different in the two cases.
 var handler = {
 target: o,
 get: function(receiver, name) {
 return this.target[name];  // Same as
 Proxy.Handler.prototype.get
 }
 }

 If you get rid of the get trap (you need a getOwnPropertyDescriptor
 trap though), the default get (derived) trap will be called instead and
 basically do what you do afterward (call to getOwnPropertyDescriptor
 trap which will call Object.**getOwnPropertyDescriptor(this.**target,
 name)+d.get.call(receiver)). The 'this' binding is performed by the
 engine (with the receiver as value) after the property descriptor has
 been returned (as explained in strawman:proxy_drop_receiver).

  Thanks.  I didn't realize that the default get behavior was to do what I
 put in my second handler.

 Yep. http://wiki.ecmascript.org/**doku.php?id=harmony:proxies#**
 trap_defaultshttp://wiki.ecmascript.org/doku.php?id=harmony:proxies#trap_defaults
 Besides type checking, the code is the same than yours for the get trap.
 In a way, it's reassuring that people experimenting like you do reach the
 same solution to the same problem independently.


  Still, my basic question remains, though: is it a bug that a forwarding
 proxy created with Proxy.Handler behaves differently in this way (this value
 in methods is different than the this value for accessors) than the object
 to which it forwards?

 I do not think it's a bug. What happens with your code is coherent with
 ECMAScript (and apparently, the JS implementation is consistent with that
 too).
 I think that a more important question is: can you achieve what you want
 (giving the impression that this is the same for both getters/setters and
 methods) with the current proxy API?. If so, is it natural or is it a
 hack?
 Apparently, you can achieve what you want and my opinion is that the
 solution is natural (using the derived trap default behavior). Removing a
 trap to achieve your goal may sound not natural, but strawman:derived_traps_
 **forwarding_handler seems to be a decent solution for that.



  (Originally I had a second question about the proposed removal of the
 receiver argument, but now I understand that that strawman is contingent on
 the addition of a proxy argument to the handler methods, so let's disregard
 that second question...)

 Yes, I'm sorry, I should have mentionned that. I tend to consider this
 strawman as already accepted since it sounds so natural to me and has found
 several justifications on es-discuss. It is however true it still needs to
 be accepted (July TC-39 meeting, hopefully?) and SpiderMonkey will need to
 be adjusted consequently.


 David
 __**_
 es-discuss mailing list
 es-discuss@mozilla.org
 https://mail.mozilla.org/**listinfo/es-discusshttps://mail.mozilla.org/listinfo/es-discuss

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