littledan / proposal-proxy-transparent

Transparent Proxies--tunneling private fields, etc.
8 stars 0 forks source link

Feedback from the SES meeting #3

Open caridy opened 6 years ago

caridy commented 6 years ago

Participants: DE, CP, JFP, DT, KS, AV, BW

Notes:

Suggestions

jridgewell commented 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.

ljharb commented 6 years ago

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)

caridy commented 6 years ago

@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.

caridy commented 6 years ago

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".

jridgewell commented 6 years ago

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?

littledan commented 6 years ago

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.

p-bakker commented 5 years ago

@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:

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

davismj commented 5 years ago

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.

caridy commented 5 years ago

@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?
``