rdking / proposal-proxy-transparency

A repo for exploring and creating a proposal to address transparency issues in the ES Proxy design.
1 stars 0 forks source link

Should `resolve` be allowed to return any object? #2

Open rdking opened 5 years ago

rdking commented 5 years ago

@mbrowne wrote:

I'm not really sold on the original idea here...do proxies really need to have the power to arbitrarily change the target to any object? If sticking with the general approach of a resolve() method, what if you just returned true or false indicating whether or not the operation should tunnel (instead of returning an object)?

I did see @ljharb's comment about multiple targets already being one of the intended use cases for proxies, which is fine for public slots (I'm assuming "public slots" is a valid term—perhaps I should just say public properties), but when internal slots get involved, I suspect there will be a host of potential encapsulation issues and other complexities that would otherwise be avoided.


I thought about that a couple of days after my suggested changes in 106. I really don't like the idea of the resolve function being able to return any arbitrary object. At the same time, I have to take into account the intent @ljharb mentioned. What I need to know is whether or not that intent extends to internal slots. If I go by the current functionality, I'd wager that the intent should not be extended that far, and that it's ok to reduce the return value of resolve to a boolean. That would make me a lot happier. If, however, the intent must be extended to internal slots, then we don't have much wiggle room.

Originally posted by @rdking in https://github.com/rdking/proposal-proxy-transparency/issues/1#issuecomment-486686454

mbrowne commented 5 years ago

If someone on the committee can clarify this now, then great (although I doubt any one committee member really knows how all the other members will feel about any particular issue). Otherwise, when you get to the point of writing up a proposal, I recommend having resolve() return a boolean. It can always be changed if you get a lot of feedback saying that's insufficient.

mbrowne commented 5 years ago

BTW @rdking, have you reviewed these issues? https://github.com/littledan/proposal-proxy-transparent/issues/3 https://github.com/littledan/proposal-proxy-transparent/issues/4 https://github.com/littledan/proposal-proxy-transparent/issues/5

They definitely provide more details on the concerns of the committee.

rdking commented 5 years ago

I tend to agree on this issue. I get that Proxy was intended to be multi-target, but to much of its existing design contradicts that, especially the invariant checks that reference [[Target]] instead of checking against the results of calling the appropriate [[Handler]] methods. If Proxy was truly meant to be multi-target, then the [[Handler]] methods would be the primary authority for the data used to verify the invariants.

@ljharb @littledan @erights @jridgewell @caridy Can any of you provide some insight on this? Or if not, can you suggest someone who can?

erights commented 5 years ago

I am confused by the "intended to be multi-target". I do not recall such an intention, nor do I have any intention now that I would describe this way. @tvcutsem , did you and I discuss such a goal? Does it ring a bell? If so, can you explain what our intention was?

rdking commented 5 years ago

See https://github.com/tc39/proposal-class-fields/issues/106#issuecomment-485053792 for the source of that notion.

erights commented 5 years ago

This does not directly ring a bell, but it does have overlap with something that is definitely a goal of proxies: That there may not be an actual target object that the proxy emulates. For example, the proxy may be part of an interpreter that implements an apparent object meta-interpretively, and uses the proxy for refraction --- for presenting this meta-level object to peers at its own base level as if it were a base-level object. IIUC, this is what Shape Security are doing. Attn @michaelficarra

However, the story told by the proxy, about the fictional object, must be a consistent story as if it is about the same object over time. Hence, the shadow technique is exactly right to ensure that the proxy's story makes sense.

ljharb commented 5 years ago

One common use case I’ve heard is multiple inheritance, where there may be more than one object the Proxy is intending to dispatch to.

rdking commented 5 years ago

So the long and short is that it is safe to assume that, at least from the Proxy's internal implementation's point of view, Proxy is a single target object?

erights commented 5 years ago

One common use case I’ve heard is multiple inheritance, where there may be more than one object the Proxy is intending to dispatch to.

That makes sense, especially as the invariants we're enforcing are very strong on "own" issues and purposely weak on inherited issues. The proxy has much more freedom to tell a strange inheritance story. However, to be clear, being weak on inherited invariants was intentional but doing so in order to enable multiple inheritance was, IIRC, not specifically intentional.

ljharb commented 5 years ago

From the Proxy consumer’s point of view. The Proxy itself can maintain that fiction however it likes.

erights commented 5 years ago

So the long and short is that it is safe to assume that, at least from the Proxy's internal implementation's point of view, Proxy is a single target object?

Modulo that there may not actually be such an object, other than as a figment of the proxy's imagination, yes.

rdking commented 5 years ago

I think that settles the multi-target issue, but after reading the articles @mbrowne posted, I wonder about the case of shadow-targets. I use that technique for several reasons myself. So here's my question:

Are there any reasons why a Membrane-like Proxy might need to alter the receiver before the access attempt?

erights commented 5 years ago

Are there any reasons why a Membrane-like Proxy might need to alter the receiver before the access attempt?

I don't understand the question. What does "alter the receiver before the access attempt" mean? Can you give an example? Thanks.

rdking commented 5 years ago

What I'm saying is that before an Invariant object function or an internal slot (other than [[Target]] & [[Handler]]) is accessed, a receiving object is checked to see if it's a Proxy that has a "resolve" handler. If so, that handler is called and the returned object becomes the new "receiving object" for the remainder of the process (the normal access protocol).

erights commented 5 years ago

There are a lot of new concepts here that do not seem directly related to or derived from the existing proxy system. Or perhaps I am just not understanding yet. The existing concept of "receiving object" is the receiver argument to the [[Get]] and [[Set]] traps. Do you mean those?

rdking commented 5 years ago

Yes. The receiving object is the LHS argument for the . operator, the object against which the operation is being made, the initial object used to call an invariant function or access an internal slot.

erights commented 5 years ago

As far as I remember, all the invariants are checked only against the shadow. What invariants are checked against the receiver?

rdking commented 5 years ago

My mistake. When I said "invariant function" I should have said "essential internal function".

erights commented 5 years ago

Example of "essential internal function"?

rdking commented 5 years ago

ES Spec 6.1.7.2 Table 5

erights commented 5 years ago

Ok, got it. I'm looking at https://tc39.github.io/ecma262/#table-5 . Yes, I know those functions.

I now understand your question at https://github.com/rdking/proposal-proxy-transparency/issues/2#issuecomment-486722392

Are there any reasons why a Membrane-like Proxy might need to alter the receiver before the access attempt?

Not that I know of. However, you and others clearly have use cases in mind that I do not. Do you have any such reasons?

mhofman commented 5 years ago

My understanding is that a membrane that unwraps and counter-wraps everything properly is already fully transparent for the targets. resolve isn't needed for them.

The problem is more with observer-type proxies. Is there any use cases for them to do things like shadow target or multiple targets?

rdking commented 5 years ago

There are indeed use cases that would require an observer Proxy to shadow targets. But that's not an issue. If the target containing private fields is being shadowed, then the Proxy handlers have to directly interact with the target instead of using Reflect methods. Done that way, there won't be an issue with the private fields. The only time we're going to have a problem is with unshadowed observer Proxy objects.

mhofman commented 5 years ago

Just to make sure I got my terminology right, this is what I understand by shadow target:

const realTarget = { foo: 1 };
const handler = {
  get(shadowTarget, prop, receiver) {
    return Reflect.get(realTarget, prop, receiver);
  }
};
const proxy = new Proxy({}, handler);
console.log(proxy.foo); // 1

If the target containing private fields is being shadowed, then the Proxy handlers have to directly interact with the target instead of using Reflect methods.

Isn't that the prerogative of membrane-type proxies?\ If typeof realTarget[prop] == "function" on a get trap, then you can't simply leave it at that, but you need to wrap the retval in a proxy that will apply the realTarget as thisArg when called. And that's not even getting into handling arguments.\ I thought the point of observer-type proxies was to always have this be the proxy object, so you can observe the effects of the target's implementation. Maybe I'm just missing something?

mbrowne commented 5 years ago

Did this discussion move somewhere else or did it just stop?

rdking commented 5 years ago

Sorry. I dropped the ball here. Had a few personal losses over the past 2 months. Just now trying to pull things back together and get things going again.

rdking commented 5 years ago

To answer @mhofman's 2-month old question: the reason is because sometimes it is necessary that this is not modified at all. Those modifications still need to go somewhere. This is the case for any private property implementation. The object in the WeakMap is essentially a shadow object.

mhofman commented 5 years ago

Sorry, I'm a little out of the loop on this conversation.

Let me know if my summary is right:

@rdking, what you mention seem to be a regular observer type proxy, without shadow or multiple targets, right?

rdking commented 5 years ago

Correct. All other Proxy types should be able to manage themselves.