Open rdking opened 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.
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.
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?
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?
See https://github.com/tc39/proposal-class-fields/issues/106#issuecomment-485053792 for the source of that notion.
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.
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.
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?
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.
From the Proxy consumer’s point of view. The Proxy itself can maintain that fiction however it likes.
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.
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?
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.
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).
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?
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.
As far as I remember, all the invariants are checked only against the shadow. What invariants are checked against the receiver?
My mistake. When I said "invariant function" I should have said "essential internal function".
Example of "essential internal function"?
ES Spec 6.1.7.2 Table 5
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?
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?
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.
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?
Did this discussion move somewhere else or did it just stop?
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.
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.
Sorry, I'm a little out of the loop on this conversation.
Let me know if my summary is right:
resolve
function as they need to wrap the methods of the proxied object anyway, and are fully transparent.resolve
function returning an object different than the proxy's target make sense for observer-type proxies?@rdking, what you mention seem to be a regular observer type proxy, without shadow or multiple targets, right?
Correct. All other Proxy types should be able to manage themselves.
@mbrowne wrote:
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