[Harmony Proxies] Proposal: Property fixing

David Bruant david.bruant at labri.fr
Fri Jun 17 12:41:32 PDT 2011


Le 17/06/2011 16:51, Tom Van Cutsem a écrit :
> 2011/6/17 David Bruant <david.bruant at labri.fr
> <mailto:david.bruant at labri.fr>>
>
>     Le 17/06/2011 08:31, Brendan Eich a écrit :
>
>         On Jun 16, 2011, at 10:12 PM, Mark S. Miller wrote:
>
>             I agree. Sounds like a proxy. Glad we worked out the
>             configurability issues.
>
>
>         Assuming Tom's fixed properties proposal (the latest) is
>         approvied -- right?
>
>     I think that there are still pending issues.
>     One is figuring out why the ES5 invariants on abnormal+non-native
>     object properties configurability are in the spec. If we assume
>     they're legitimate, then we're pretty much done (not 100%, see below)
>     As far as I'm concerned, I haven't read arguments enforcing a
>     belief that these invariants on abnormal+non-native objects really
>     have a value and why all implementations should follow them (Once
>     again, they are in the spec, so they should be respected by
>     implementors. But should they be in the spec? What is the added
>     value of these 5 invariants? Why no other invariant?)
>
>     For the moment, apparently, two cases are problematic:
>     - A forwarding proxy cannot fully forward, because it cannot
>     honestly tell whether a property in the target object is
>     configurable or not (it will always pretend it's configurable).
>     Since the forwarding proxy pattern is probably the most important,
>     this seems to be a major issue.
>
>
> I agree there doesn't seem to be a generic solution. However,
> strawman:fixed_properties does make it possible for forwarding proxies
> to deal with certain cases:
> - if target has a non-configurable accessor property, the proxy can
> create a fixed non-configurable accessor whose get/set attributes
> invoke handler.get/set, as shown on the strawman page.
Actually, for this very case, you could take the getter and setter of
the target property and use them for the fixed proxy property (since
they won't change on the target). It would solve the asymetry that comes
from calling handler.get/set when the non-configurable proxy property is
an accessor and not calling these traps when it's a data property.

> - if target has a non-writable, non-configurable data property
> (typically a property just acting as a constant), the proxy can create
> its own fixed copy of that property. IINM, non-writable
> non-configurable properties can't change, so the copies cannot grow
> out of sync.
No issue with constants, indeed.

> - if target has a writable, non-configurable data property, the proxy
> could create a fixed copy. In its defineProperty trap, it has to make
> sure to forward the defineProperty operation to the target, in case
> its writable property is switched from true to false. The one thing
> the proxy cannot intercept are changes made to the original property
> on its |target|. I.e. the proxy may still advertise its fixed property
> as {writable:true, configurable:false} while the target's property may
> have been changed to {writable:false,configurable:false} by some other
> code.
Symetrically to the forwarding of defineProperty, maybe that
getOwnPropertyDescriptor could be forwarded too (requires to call the
getOwnPropertyDescriptor trap for non-configurable properties) and the
return value could be used to redefine writable on the proxy fixed
property if necessary.
-----
var t = Object.create(null, {a:{value:1, configurable:false,
writable:true}});
var p = ForwardingProxy(t);
// p has a fixed property 'a'.
Object.getOwnPropertyDescriptor(p, 'a');
// {value:1, configurable:false, writable:true, enumerable:false}

Object.defineProperty(t, 'a', {value:1, configurable:false,
writable:false});

Object.getOwnPropertyDescriptor(p, 'a');
// Currently unchanged as you said: {value:1, configurable:false,
writable:true, enumerable:false}
// because the trap is not called.
// My suggestion is that the getOwnPropertyDescriptor trap should be called
// In that case, it would forward to the target and return the correct
target property descriptor
// {value:1, configurable:false, writable:false, enumerable:false}
// Since the pd cannot be returned right away without risking to violate
some invariants,
// the engine should check whether the returned pd can replace the
current pd
// without violating an invariant.
// In that case, changing writable from false to true of a
non-configurable property is legitimate.
// The engine changes the fixed property descriptor with the returned
one (reject if the wanted
// change violates an invariant) and actually return to the program this
invariant.
-----

>
>     Also, trying to create a non-configurable property on the target
>     will not be possible (unless using custom property descriptor
>     attribute? :-s), because with the fixed property proposal, such a
>     property get stuck at the proxy level. No trap is called, no
>     forwarding.
>
>
> My latest addition to the proposal would allow proxy handlers to still
> intercept defineProperty, even on fixed properties, so they could
> propagate changes to fixed properties to their target.
That's what I was missing. Propagating getOwnPropertyDescriptor is the
symetric idea.



>  
>
>     - Issue with a proxy saying that an inherited property is a
>     non-configurable property (getPropertyDescriptor trap). Basically,
>     getPropertyDescriptor may say that a property is configurable
>     while getPrototypeOf+getOwnPropertyDescriptor(on a native object
>     which allows non-configurable property) may say that the property
>     is not-configurable. They would both talk about the same property
>     and be inconsistent.
>
>
> Yes, this is a thorny issue. We could drop the getPropertyDescriptor
> operation & trap. What we lose by that is that proxies would be unable
> to fully emulate inherited properties. That is: while a proxy's
> get/set traps may still emulate "foo" as an inherited property (i.e.
> proxy.foo returns a value, but
> Object.getOwnPropertyDescriptor(proxy,'foo') returns undefined), the
> illusion would be broken once the proxy's inheritance chain is
> inspected (i.e. code may find out that there's actually no "foo"
> property on the proxy's prototype chain). Actually, one could argue
> that even without getPropertyDescriptor proxies already cannot emulate
> prototype inheritance, since they can't virtualize Object.getPrototypeOf.
For the getPropertyDescriptor trap, if the returned descriptor has
"configurable:false", the engine could climb the prototype chain to
check that "configurable:false" is actually legitimate (only
configurability). May be costly?



To summurize fixed propeties property-specific trap behaviors, one could
say that:
- defineProperty trap is called (and its return value is meaningful as
explained on the current strawman)
(if approved) - getOwnPropertyDescriptor trap is called (and its return
value is meaningful the same way)
- delete rejects
- All other property-specific traps have the default derived trap
behavior (all the remaining property-specific traps are derived).

Does that sounds right?

David
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20110617/7753ff5a/attachment-0001.html>


More information about the es-discuss mailing list