2012/12/30 Allen Wirfs-Brock <al...@wirfs-brock.com> > > On Dec 29, 2012, at 2:37 PM, Tom Van Cutsem wrote: > > * I'm a bit uncomfortable with the removal of property descriptor > normalization in the getOwnPropertyDescriptor/defineProperty traps. > Especially for getOwnPropertyDescriptor I think it's a breaking change > w.r.t. ES5.1. > [...]
This permits things like: > > Object.defineOwnProperty(pObj1,"foo", {method: func}); //define property > on a proxy-based object, that have "method" properties > console.log (Object.getOwnPropertyDescriptor(pObj1,"foo").method); //we > can retrieve the value of the method attribute (if the proxy supports it) > > Object.defineOwnProperty(pObj2,"foo",Object.getOwnProperty(pObj1, "foo")); > //copy a method properry from pObj1 to pObj2 > > If descriptor object with extended attributes is applied to an ordinary > object, it is always first internally converted to a PD record. PD records > only contain fields for the ordinary attributes, and any operations upon > ordinary objects will have no visibility of the extended attributes. > Yes, I agree to all of this and I understand this is the intent of the new [[Origin]] field of internal property descriptors. I also agree there's no problem for normal objects, which continue to always cons a fresh property descriptor object. > The only breaking change (relative to ES 5.1) possibility I see must start > with the assumption that ES5.1 property attributes are the final > definition of property descriptor objects and that additional property > attributes can never be added to the language (by the spec., not just via > proxies) using any of the pre-existing ES5.1 APIs. That seems quite > unreasonable and was certainly not the intent when we introduced the > reflection API into ES5. [...] This was not the breaking change I had in mind and I agree with you that adding new attributes is both useful and supported by the ES5.1 design. Here's the breaking change I had in mind: var propDescMap = {}; var proxy = Proxy({}, { defineProperty(target, name, desc) { propDescMap[name] = desc; return true; }, getOwnPropertyDescriptor(target, name) { return propDescMap[name]; } }; // client1 adds: var pd1 = { get configurable() { return Math.random() < 0.5; }, // return true or false, randomly custom: true }; Object.defineProperty(proxy, "foo", pd1); // client2 queries: var pd2 = Object.getOwnPropertyDescriptor(proxy, "foo"); If I understand correctly, pd2 now refers to exactly the same object as pd1, preserving the custom attribute. However, this semantics also implies that: 1) pd2 is not a completed property descriptor, lacking a writable/enumerable attribute. Only the internal property descriptor was fully completed, not the [[Origin]] object. 2) pd2.configurable is not a data property, but may change randomly 3) since pd1/pd2 refers to a mutable object, changes made by client1 will be visible to client2 and vice-versa. None of these behaviors are possible in ES5.1, so clients of Object.getOwnPropertyDescriptor currently don't (need to) guard against these. The issue is that in 8.5.6 Proxy [[GetOwnProperty]], only the "resultDesc" is normalized, not the trapResultObj that is its [[Origin]]. The FromPropertyDescriptor operation blindly returns the [[Origin]], disregarding the normalized descriptor. To rescue the [[Origin]] design, the most straightforward fix I can come up with is that FromPropertyDescriptor first normalizes the [[Origin]] object before returning it (i.e. verifying that it is complete, or making it complete, and ensuring the standard attributes are data properties). Even then so, it's messy that these side-effects are visible to end-user code (the pd1 object of client1 would get mutated-at-a-distance as a result of returning it from a getOwnPropertyDescriptor trap). The only other alternative I see is to create normalized copies, as specified in the draft proxy spec on the wiki. Cheers, Tom
_______________________________________________ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss