Open caridy opened 6 years ago
shadow target mechanism (which is needed for membranes) will not work with Proxy.transparent.
Can you explain this further? What's a shadow target membrane? Why will it not work?
Especially in light of your "there will be little incentive to use Proxy" makes me think that we have the wrong default implementation of Proxy.
Proxy.transparent.unwrap will cause developers to always unwrap before operations just to be sure (we have some precedent for that at Salesforce).
Agreed.
it must include Web IDL
imo it also must include all builtins - ie, it should tunnel internal slots as well. (To clarify, I say "must" there because I think the mental model is very important, and users having to distinguish between "it's a builtin" and "it's something else" is not something i think we want users to be forced to do)
@jridgewell when you build membranes, you never expose original values, you must proxy them all. E.g.:
const o = {};
const p = getProxyMembrane(o);
Object.defineProperty(o, 'x', {
value() {}
});
p.x === o.x; // yields false
In this case, the membrane is also wrapping the value of o.x
, but if the descriptor for x
is non-configurable, how can proxy p
breaks the invariants of the language? It does it because it uses something that we call "Shadow Target" instead of the original target to create the proxy.
It is an academic term at this point, but it means that when you create a proxy of an object to build a membrane around it, the value that you pass to the Proxy constructor as the first argument, is not the original target, it is an empty object that you will populate lazily to be able to wrap everything without breaking those invariants. Usually, the original target is associated to the shadow target using a weakmap, or using a handler instance that holds it in a way that is accessible in your hooks.
In the case of Proxy.transparent
, if you provide the shadow target instead of the original target so you can do some if those tricks, the engine will attempt to unwrap the wrong object. With this proposal, even if the target of the proxy is not relevant, the hook for unwrap will allow you to still return the original target so the engine can do the right thing.
imo it also must include all builtins
agreed, it should work for all kind of things, I noticed in #3 as:
internal slots, private fields and others "creatures".
In this case, the membrane is also wrapping the value of o.x, but if the descriptor for x is non-configurable, how can proxy p breaks the invariants of the language?
I'm not sure I follow. Nothing about the example breaks the invariants, a proxy can return anything it wants from the traps.
Perhaps there's something inside getProxyMembrane
that I don't understand?
In the case of Proxy.transparent, if you provide the shadow target instead of the original target so you can do some if those tricks, the engine will attempt to unwrap the wrong object.
Where are we providing the shadow target? Like, what's calling unwrap?
Thanks for inviting me to this meeting. Based on the feedback, I don't plan to present Proxy.transparent to TC39 in the July 2018 meeting.
@littledan in the previous comment you said you planned not to present this proposal based on the feedback. Am a bit unclear if that means the proposal is dead in the water or that it means that it needs more work before presenting
Now my take on things: the outset of this proposal says
but often they just want to intercept all object operations, including in methods on the object or defined in subclasses
One of the suggestions in this issue says
gather more information on why Framework authors really want to track internal operations by supplying a proxy when invoking a method or an accessor
And there are 5 notes on this issue that.
All that together doesn't seem to add up for me...
The use-case for Proxies as many devs in the community (IMHO) see it aren't membrane-style patterns but observer patterns, for example dependency or modification tracking:
I know Proxies have been designed with Membranes in mind and as such come with certain restrictions, but the community has other use-cases for proxies, mainly observability.
Looking at it from that angle, Proxies don't need to be revocable, don't need a shadow target mechanism etc. And the last note on this issue about transparent Proxies not being able to observe operations in the class constructor might be irrelevant as well (IMHO) as the code that wants to observe is either given an existing class/object instance to observe OR it instantiates the instance itself, in which case it most likely controls the utmost base classes source, thus if it needs to observe operations done in constructors, it can return a Proxy from the constructor of the utmost base class, see https://github.com/tc39/proposal-class-fields/issues/106#issuecomment-448527014 (note that that scenario already is supported with the current Proxy impl., at least when it comes to private fields). Only case where it wouldn't work would be where the code that wants to observe (including constructor operations) instantiates class instances that it itself has no control over.
So, maybe to way to go about this is to not try and squeeze this use-case into the existing Proxy implementation, but either:
new Observable(target, handler)
Object.observe(target, handler)
Making it different from Proxies like this I think also resolve the note on this issue about there will be little incentive to use Proxy
as it clearly differentiates based on purpose (interesting comment btw, given the misalignment of the perception of what proxies are between (parts of) the community and (parts of) the committee).Both variations are basically Proxies, but without revocability and with the tunneling of private fields and internal slots.
Not sure how 'big' such an approach is from a implementation point of view
Developers will have to choose between two different type of proxies, Proxy or Proxy.transparent, and there will be little incentive to use Proxy.
Can someone clarify the meaning of this? If people have to choose between A and B, and there's almost no reason for B, then why are there no plans to present A?
don't plan to present Proxy.transparent to TC39 in the July 2018 meeting.
@p-bakker
Looking at it from that angle, Proxies don't need to be revocable, don't need a shadow target mechanism
How do you observe an object like this:
const o = { foo: { bar: 1 } };
const m = observable(o);
m.foo.bar = 2; // how do you object this without a shadow target?
``
Participants: DE, CP, JFP, DT, KS, AV, BW
Notes:
Proxy.transparent
.Proxy.transparent.unwrap
will cause developers to always unwrap before operations just to be sure (we have some precedent for that at Salesforce).Proxy
orProxy.transparent
, and there will be little incentive to useProxy
.Proxy.revocable
is missing in the initial proposal. A proxy can be transparent and revocable.Proxy.transparent
, assumptions that all operations can be observed are not accurate. e.g.:constructor() { callMeBack(() => this.x += 1; ) }
can't be observed.Suggestions