Property descriptor normalization (Was: General comments response (was Re: ES6 Rev13 Review: MOP-refactoring, symbols, proxies, Reflect module))

Tom Van Cutsem tomvc.be at gmail.com
Mon Dec 31 03:37:04 PST 2012


2012/12/30 Allen Wirfs-Brock <allen at 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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20121231/87f71095/attachment.html>


More information about the es-discuss mailing list