Removing Proxy hasOwn() trap (Was: [[Invoke]] and implicit method calls)

# Tom Van Cutsem (11 years ago)

[forking from [[invoke]]-thread for clarity]

2013/9/23 Jason Orendorff <jason.orendorff at gmail.com>

On Mon, Sep 23, 2013 at 3:40 AM, Tom Van Cutsem <tomvc.be at gmail.com> wrote:

To me hasOwn() is as much a primitive as e.g. Object.keys().

The only odd thing about it is that it lives on Object.prototype rather than as a static method on Object.

I don't see the inconsistency, unless you would also want to remove Object.keys() because it can be expressed in terms of gOPN + gOPD.

But Tom, there already is no trap for Object.keys()! It's specified in terms of [[OwnPropertyKeys]] and [[GetOwnProperty]].

My bad. I was still looking at the wiki page, which is outdated in that respect.

Given the Object.keys precedent, we could consider removing hasOwn() and re-specifying it in terms of getOwnPropertyDescriptor() !== undefined.

More object allocation, but the same holds true for removing the "keys" trap.

Allen: would the removal of the hasOwn() trap imply that we can drop the [[HasOwnProperty]] internal method altogether?

# Jason Orendorff (11 years ago)

On Tue, Sep 24, 2013 at 7:23 AM, Tom Van Cutsem <tomvc.be at gmail.com> wrote:

[forking from [[invoke]]-thread for clarity]

Thanks!

Allen: would the removal of the hasOwn() trap imply that we can drop the [[HasOwnProperty]] internal method altogether?

I searched the spec. There are not very many places where [[HasOwnProperty]] is used; each one can be replaced with a call to an Abstract Operation defined like this:

When the abstract operation HasOwnProperty is called with Object O and property key P, the following steps are taken:

  1. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with argument P.
  2. ReturnIfAbrupt(desc).
  3. If desc is undefined, then return false.
  4. Return true.

This allows five or six sections defining [[HasOwnProperty]] implementations to be deleted. It's a nice simplification.

# Allen Wirfs-Brock (11 years ago)

On Tue, Sep 24, 2013 at 7:23 AM, Tom Van Cutsem <tomvc.be at gmail.com> wrote:

Allen: would the removal of the hasOwn() trap imply that we can drop the [[HasOwnProperty]] internal method altogether?

I look at the the opposite way -- we have an 'hasOwn' trap because be have a [[HasOwnProperty]] internal method ;-)

I pretty sure we discussed this before and decided we wanted to keep [[HasOwnProperty]]. However, the only reason I can think of for doing so now is to avoid forcing exotic objects to allocated the property descriptors that [[GetOwnProperty]] produces.

On Sep 24, 2013, at 8:13 AM, Jason Orendorff wrote:

I searched the spec. There are not very many places where [[HasOwnProperty]] is used; each one can be replaced with a call to an Abstract Operation defined like this:

Right, an none of the places seem particularly performance sensitive. In particular, ordinary property lookup uses [[GetOwnProperty]] rather than [[HasOwnProperlty]]

This allows five or six sections defining [[HasOwnProperty]] implementations to be deleted. It's a nice simplification.

Yes, I'm a big fan of minimizing the number of MOP functions. However, I'm a bit uneasy that I can't recall specifically why it is still there. I'm pretty sure we've discussed this before.

# André Bargull (11 years ago)

I look at the the opposite way -- we have an 'hasOwn' trap because be have a [[HasOwnProperty]] internal method ;-)

I pretty sure we discussed this before and decided we wanted to keep [[HasOwnProperty]]. However, the only reason I can think of for doing so now is to avoid forcing exotic objects to allocated the property descriptors that [[GetOwnProperty]] produces.

Exotic string and integer indexed objects ( = TypedArray instances) provide custom implementations for [[HasOwnProperty]] for exactly this reason.

Right, an none of the places seem particularly performance sensitive. In particular, ordinary property lookup uses [[GetOwnProperty]] rather than [[HasOwnProperlty]]

[[HasProperty]] for ordinary objects also uses [[HasOwnProperty]]. So this needs to be taken into account when searching for performance sensitive calls.

# Allen Wirfs-Brock (11 years ago)

On Sep 24, 2013, at 12:15 PM, André Bargull wrote:

Exotic string and integer indexed objects ( = TypedArray instances) provide custom implementations for [[HasOwnProperty]] for exactly this reason.

And because of proxies, a specified call to [[GetOwnProperty]] can't be optimized away unless you're sure you are dealing with an ordinary object.

[[HasProperty]] for ordinary objects also uses [[HasOwnProperty]]. So this needs to be taken into account when searching for performance sensitive calls.

and most of those [[HasProperty]] calls in the spec. are abstracted within the HasProperty abstract operation, so that also needs to be taken into account.

# Jason Orendorff (11 years ago)

Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

On Sep 24, 2013, at 12:15 PM, André Bargull wrote:

On Tue, Sep 24, 2013 at 2:34 PM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

I pretty sure we discussed this before and decided we wanted to keep [[HasOwnProperty]]. However, the only reason I can think of for doing so now is to avoid forcing exotic objects to allocated the property descriptors that [[GetOwnProperty]] produces.

Exotic string and integer indexed objects ( = TypedArray instances) provide custom implementations for [[HasOwnProperty]] for exactly this reason.

And because of proxies, a specified call to [[GetOwnProperty]] can't be optimized away unless you're sure you are dealing with an ordinary object.

Here are three ways implementations can avoid this allocation.

  1. We are usually sure we’re dealing with an ordinary object! The only performance-sensitive call site is in [[HasProperty]] for ordinary objects, and there it is of course given that O is ordinary. An implementation can easily avoid the allocation in this case.

  2. In all HasOwnProperty call sites, the object will normally be ordinary. Implementations can optimize for that case using the same techniques they already use for everything else in the language.

  3. An implementation can certainly have an Object::hasOwnProperty virtual method, if it’s faster, even if the spec calls it an abstract operation rather than an internal method. Proxy::hasOwnProperty would have to call the getOwnPropertyDescriptor trap; all other implementations could avoid the allocation.

I hope my point here is clear. There’s no performance reason to retain the .hasOwn trap or [[HasOwnProperty]].

# Tom Van Cutsem (11 years ago)

I recall that Allen and I had previously agreed that it would be cleanest if each of the [[internal]] methods on Object would correspond 1-to-1 to a trap in the Proxy API (and I believe this is the case for the current ES6 draft).

So my stance is that we should either remove both hasOwn() and [[HasOwnProperty]], or else remove neither.

I'm fine either way, but I believe Jason is right that [[HasOwnProperty]] can be refactored as an abstract operation without any perf implications on non-proxy objects.

# Allen Wirfs-Brock (11 years ago)

On Sep 25, 2013, at 1:26 AM, Tom Van Cutsem wrote:

I recall that Allen and I had previously agreed that it would be cleanest if each of the [[internal]] methods on Object would correspond 1-to-1 to a trap in the Proxy API (and I believe this is the case for the current ES6 draft).

So my stance is that we should either remove both hasOwn() and [[HasOwnProperty]], or else remove neither.

Of course, I had assumed that is implicit in the discussion.

I'm fine either way, but I believe Jason is right that [[HasOwnProperty]] can be refactored as an abstract operation without any perf implications on non-proxy objects.

I think so too. Since there doesn't seem to be any objections I'll tag [[HasOwnProperty]] for the scrap heap.