Property Descriptors as script compatible representation
Le 02/11/2012 12:20, Tom Van Cutsem a écrit :
Hi Allen,
2012/11/1 Allen Wirfs-Brock <allen at wirfs-brock.com <mailto:allen at wirfs-brock.com>>
The above isn't how this will be expressed in the final spec. Instead we will have 3) Let desc be the result of calling the [[GetOwnProperty]] internal method of O with argument name. 4) Return the result of calling FromPropertyDescriptor(desc) (8.10.4). And all Proxy objects will have a [[GetOwnProperty]] internal methods that looks something like: 1) Let O be the object upon which this internal method was invoked. 2) Let desc be the result of calling TrapGetOwnProperty(O,name) 3) Return ToPropertyDescriptor(desc) (I left out details of exception handling)
Actually, while reviewing the spec, I realized that there is a good reason why the spec isn't currently specified this way (i.e. why the Proxy spec redefines Object.defineProperty and Object.getOwnPropertyDescriptor and does not just override [[DefineOwnProperty]] and [[GetOwnProperty]])
It is to avoid the lossy conversion that otherwise occurs between the return value of [[GetOwnProperty]] and Object.getOwnPropertyDescriptor.
Just to be sure I fully understand: what is the loss exactly? I see that custom property descriptor attributes would be stripped out (because FromPropertyDescriptor outputs an object with 4 props mapping 1-to-1 to an accessor or data property descriptor). Is there another loss?
If that's the only thing, redefining the property descriptor type to accept any field would prevent that loss. Such a change would be more aligned with the intention in the proxy spec of letting internal operations manipulate custom attributes passed to Object.defineProperty.
I'm arguing in favor of switching to a script-usable type, but the change I mention can occur in the spec-only type.
2012/11/2 David Bruant <bruant.d at gmail.com>
Le 02/11/2012 12:20, Tom Van Cutsem a écrit :
It is to avoid the lossy conversion that otherwise occurs between the return value of [[GetOwnProperty]] and Object.getOwnPropertyDescriptor.
Just to be sure I fully understand: what is the loss exactly? I see that custom property descriptor attributes would be stripped out (because FromPropertyDescriptor outputs an object with 4 props mapping 1-to-1 to an accessor or data property descriptor). Is there another loss?
No, just the loss of custom attributes.
If that's the only thing, redefining the property descriptor type to accept any field would prevent that loss. Such a change would be more aligned with the intention in the proxy spec of letting internal operations manipulate custom attributes passed to Object.defineProperty.
I'm arguing in favor of switching to a script-usable type, but the change I mention can occur in the spec-only type.
I went ahead and refactored the Proxy spec to inline Aux.3 NormalizePropertyDescriptor and Aux.4 NormalizeAndCompletePropertyDescriptor [1]. The new behavior is identical except that:
- both TrapGetOwnProperty and TrapDefineOwnProperty do one less needless conversion from Object to PropDesc
- both TrapGetOwnProperty and TrapDefineOwnProperty can now do all invariant checks against an internal PropDesc instead of against a normalized property descriptor Object
- in TrapGetOwnProperty, we can defer conversion from PropDesc to Object, and copying of custom attributes, to the last possible moment, only after all the invariant checks succeed.
To my mind, this refactoring further reduces the need for some new script-usable property descriptor type.
Cheers, Tom
Le 02/11/2012 16:39, Allen Wirfs-Brock a écrit :
So, yes, in that case Object.getOwnPropertyDescriptor and Object.defineProperty need to pass through object level descriptors from/to the corresponding proxy traps which means they can't normalize via a property descriptor record. So, it is perfectly appropriate for them to explicitly test if O is a proxy and act accordingly. I think, this should be the only place where an explicit Proxy test is required outside of the actual proxy object specification algorithms.
For some time after this sentence I wondered what justified Object.getOwnPropertyDescriptor and Object.defineProperty to have special-casing for proxies. The reason is that proxies have an additional ability that regular objects don't: accepting custom attributes. More specifically, proxies are expected to be able to regurgitate custom attributes on Object.getOwnPropertyDescriptor after they've been set with Object.defineProperty.
Then, I wondered why it matters that only proxies can do it. The reason is future-proofing. If a property descriptor record accepts any key and value besides the standards ones, then it may become impossible to extend property descriptor records in the future by assigning semantics to currently-unused field names.
Keeping property descriptor records as tightly defined is for the best for the future.
Le 02/11/2012 09:33, Tom Van Cutsem a écrit :
Since the mutability would be limited by invariant enforcement, I don't think it would be a problem. Maybe this problem is bigger than I see it?
Arguably, if there is a construct that represent property descriptors, it may no longer be necessary to return a fresh object each time.
No. What's needed is an algorithm to normalize the descriptor. The conversion is just a convenience to reuse the spec algorithm. The other alternative would be to duplicate the logic to make it applicable to ECMAScript objects. I'm not satisfied with any of these choices (but apparently I'm the only one)
Tell me if I'm wrong, but if implementations can get rid of the extra allocation, so could the spec, no? (that's what Allen suggests in his answer).