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