Proxies fail comparison operator

# Michael Lewis (7 years ago)

Hello community,

The proxy is almost an identical to the underlying object, but it* fails a comparison check with the underlying object.*

This means that if anyone gets a reference to the underlying object before it is proxied, then we have a problem. For example:

var obj = {}; var proxy = new Proxy(obj, {}); obj == proxy; // false

Isn't the purpose of the proxy to be exchanged with the original*, without any negative side effects? *Maybe that's not the intended use case, but it's a useful one. And, besides the comparison, I can't think of any other "negative side effects".

It seems like the Proxy could have a comparison trap. The comparison could pass by default, and you could use the trap if you wanted to make proxy == obj fail.

Also, a slight tangent: it would be awesome if you could *skip debugging proxy traps when stepping through code. *When you proxy both get and apply for all objects/methods, you have 10x the work when trying to step through your code.

I just subscribed to this list. Is this an appropriate venue for this type of inquiry? I appreciate any feedback.

Thanks!

Michael

# Jordan Harband (7 years ago)

I don't believe Proxies are designed to give you any encapsulation to a user who also has a reference to the target object - you'd have to never provide the reference to the target object in the first place.

# Michael Lewis (7 years ago)

I don't believe Proxies are designed to give you any encapsulation to a user who also has a reference to the target object

So the Proxy wasn't designed to proxy real objects that operate with real code?

myRealFunction(obj) <---> myRealFunction(proxy)

This could be incredibly useful. You could log every get/set/method call on the obj. And, this will work in 99% of use cases. Just cross your fingers that your code doesn't use the comparison operator.

you'd have to never provide the reference to the target object in the first

place.

Yea, that's what I'm doing. But inside a constructor, you basically have to create the proxy first thing, call all initialization logic on the proxy instead of this, and return the proxy. And when you're only proxying if log: true has been set, you have to maybe proxy, but maybe not. I can work around it, but I'm not happy about it ;)

ljharb ftw! (I am delevoper on IRC, the one frequently ranting about the software revolution)

# Oriol _ (7 years ago)

Isn't the purpose of the proxy to be exchanged with the original, without any negative side effects?

This is not possible. Proxies do not reflect internal slots, so for example, in a browser,

var obj = document;
var proxy = new Proxy(obj, {});
Node.prototype.contains.call(obj, obj); // true
Node.prototype.contains.call(proxy, proxy); // TypeError: 'contains' called on an object that does not implement interface Node.

So it would be bad if obj === proxy returned true but the values had different behaviors. I think +0 === -0 despite 1/+0 !== 1/-0 is already enough of a nightmare.

# Alex Vincent (7 years ago)

You really don't want proxies to equal their underlying objects: proxies can show properties that the underlying object doesn't have, hide properties that the underlying object does have, alter the appearance of other proxies, etc.

What you probably want is to never deal with the underlying object in the first place, unless you absolutely have to. That's why you'd create a proxy anyway...

Have you heard about membranes? I've talked about them on this list recently, as have several others over the years...

I don't intend to toot my own horn too much, but you might want to check out my es7-membrane project: ajvincent/es7-membrane

Alex

From: Michael Lewis <mike at lew42.com>

# Allen Wirfs-Brock (7 years ago)

For background

# Michael Kriegel (7 years ago)

I agree with everyone, that the proxy object should not equal the proxied object.

What you really want to ask for is for JavaScript support for overriding the comparison operator for a class. (and other operators, too...)

# Michael Lewis (7 years ago)

Proxies do not reflect internal slots (Oriol)

You really don't want proxies to equal their underlying objects:

proxies can show properties that the underlying object doesn't have, hide properties that the underlying object does have, alter the appearance of other proxies, etc. (Alex Vincent)

What you really want to ask for is for JavaScript support for overriding

the comparison operator for a class. (and other operators, too...) (Michael Kriegel)

Sounds like the purpose of Proxies evades me and unfortunately, I don't have time to read up on it, but thanks for the link, Allen. Any article that begins with the word abstract scares me.

Yes, Michael, I think operator traps for the proxies would be a perfect solution. Then I could let my proxies === my targets, woohoo!

Thanks everyone, great feedback.

# Alexander Jones (7 years ago)

I would really hope that === can never be trapped. So much code would break! (Then again, I thought that about toString... :/)

# Michał Wadas (7 years ago)

Proxies being able to intercept strict equality would be nightmare - WeakMap and WeakSet would need new semantics, potentially incompatible with previous one. Engines won't be able to optimize certain boolean expressions because of potential side effects.

The only thing I can think of is not-a-trap:

const foo = {}; const bar = new Proxy({}, { equals: foo }); bar === foo; // true bar === {}; // false

But even that can lead to many problems with design (how about new Proxy({}, {equals: bar})

# Mark S. Miller (7 years ago)

The Left Hand of Equals research.google.com/pubs/pub45576.html is relevant to this discussion. The advice in this paper should be considered new languages that are not yet committed to an equality semantics. Frankly I have mixed feelings about it, but it is fascinating.

OTOH, for JavaScript, === must not trap.

Enjoy.