Not own property getters

# Alex Kodat (7 years ago)

In a previous post I had proposed an Object.guard (originally badly named as Object.lock) to make it possible to catch references to non-existent properties in code that uses an object.

While that proposal didn't exactly generate a lot of enthusiasm, I now realize that there would be a better way of accomplished what I had proposed with a more general purpose facility. Specifically, if there were an Object.notOwnPropertyValue(<object>, <getter>) function that indicated a

getter to be invoked on a request for a not own property of the object. If a request for a not own property of <object> is received <getter> is called

with this set to the receiver and the only argument set to the requested property.

My proposed Object.guard function could just be accomplished by something like

Object.notOwnPropertyValue(myObject, (prop) => {throw Error("Bad

property: " + prop);})

For the purposes of catching bad property references, this is better than my previous proposal because it eliminates the need for [[Get]] (P, Receiver) to maintain a guard barrier state as it works it way down the prototype chain. Instead, if someone wanted to not throw for properties on the prototype chain, the notOwnPropertyValue getter could itself check for the property in the receiver's prototype chain:

Object.notOwnPropertyValue( myObject, (prop) => { if (prop in Object.getPrototypeOf(myObject) return Object.getPrototypeOf(myObject)[prop]; throw Error("Bad property: " + prop); } }

Obviously this could be done more tidily and efficiently but hopefully the point is clear.

A simple alternative use (to a bad property reference catcher) of this capability would be something like

let counts = {}; Object.notOwnPropertyValue(counts, () => 0); someStringArray.forEach((s) => counts[s]++;);

Note that I suspect for most purposes one would set Object.notOwnPropertyValue on a prototype so there'd be no cost to getting a property off any prototypes until a property has not been found yet when we get to a prototype with Object.notOwnPropertyValue set. So for my purposes, I'd create some Guard (my own class) object that would be just above Object in the prototype chain of most of my classes that would throw on an invalid property reference (my choice whether or not to allow Object.prototype properties to be accessed via property accessors on the Guard class objects).

I believe this would be relatively simple to implement and, beyond the definition of Object.notOwnPropertyValue, would require only a minor change to the [[Get]] (P, Receiver) description in the spec:

  1. Assert: IsPropertyKey(P) is true.

  2. Let desc be O.[GetOwnProperty].

  3. ReturnIfAbrupt(desc).

  4. If desc is undefined, then Insert 1 =>. Let getter be O.[[GetNotOwnProperty]]. Insert 2 =>. If getter is not undefined return Call(getter, Receiver, P)

    a. Let parent be O.[GetPrototypeOf]. b. ReturnIfAbrupt(parent). c. If parent is null, return undefined. d. Return parent.[[Get]](P, Receiver).

  5. If IsDataDescriptor(desc) is true, return desc.[[Value]].

  6. Otherwise, IsAccessorDescriptor(desc) must be true so, let getter be desc.[[Get]].

  7. If getter is undefined, return undefined.

  8. Return Call(getter, Receiver).

An alternative would allow argument 1 of Object.notOwnPropertyValue to be a non-function value in which case it would simply be returned rather than called. In the weird case where you want the result of a not own property reference to be a function, you'd have to define a getter that returns the function. Some sort of formal memoization support would, of course, obviate the need for a non-function not own property value. So maybe the function described here should be called Object.notOwnPropertyGetter.

Implementation could be accomplished by having a slot in every object for a notOwnPropertyValue getter or by a bit indicating that there is indeed such a getter and then a hidden Symbol property that references the getter. The latter means that the cost of this feature is one bit per simple object and a bit more overhead if the bit is on. Plus, presumably Object.getOwnPropertySymbols would have to be smart enough not to display the hidden Symbol. But, this is an implementation detail.

Finally a big hand wave for now about how one implements the ability to get rid of a not own property getter -- there are a lot of ways this can be accomplished and it's not worth discussing if there's a truck-sized hole in this proposal or if someone tells me that this is the Nth time this feature has been proposed (I did find the Firefox noSuchMethod Object.prototype method). I suspect another response will be to tell me to use a proxy but that would be an insanely heavyweight way of accomplishing such a simple task.

If no one blows a hole in this proposal, I guess I'll figure out how to turn it into a formal proposal so I can be the proud owner of a stage 0 proposal.

Thanks


Alex Kodat

# Michał Wadas (7 years ago)

Why can't you use proxy for this?

# Alex Kodat (7 years ago)

If I run the following:

let foo = {a: 0, b: 1, c:1}; let bar = ( new Proxy( foo, {get: (target, prop) => { if (prop in target) return target[prop]; if (typeof prop == "symbol") return target[prop]; if (prop == "inspect") return; if (prop == "toJSON") return; throw Error("Bad property: " + prop); } } ) ); // bar = foo;

for (let i = 0; i < 1000000; i++) { bar.a = bar.b; bar.b = bar.c; bar.c = bar.c + i; }

with the bar = foo assignment above commented out (so using a proxy) and not commented out (so direct object access) and V8 (Chrome), SpiderMonkey (Firefox), and Chakra (Edge) the difference between proxy and not was about a factor of 300-500 (perhaps unsurprisingly, all the JS engines were close-ish to each other).

While perhaps this can be improved, it’s a lot to ask of an optimizer to detect a proxy and figure out what it's doing to the degree that V8 (and I suspect other browsers) detect that bar.a is always at the same offset in bar and always an integer (as long as bar's shape doesn't change) and so optimize the call to a handful of machine language instructions. Let's say some superstar gets the difference down to a factor of 20 (I suspect that's unlikely). That's still a big price to pay for detecting errors or say automatically returning 0 for an undefined property.


Alex Kodat

From: Michał Wadas [mailto:michalwadas at gmail.com] Sent: Thursday, September 7, 2017 3:55 PM To: Alex Kodat <alexkodat at gmail.com>

Cc: es-discuss at mozilla.org Subject: Re: Not own property getters

Why can't you use proxy for this?

On 7 Sep 2017 10:05 pm, "Alex Kodat" <mailto:alexkodat at gmail.com> wrote:

In a previous post I had proposed an Object.guard (originally badly named as Object.lock) to make it possible to catch references to non-existent properties in code that uses an object.

While that proposal didn't exactly generate a lot of enthusiasm, I now realize that there would be a better way of accomplished what I had proposed with a more general purpose facility. Specifically, if there were an Object.notOwnPropertyValue(<object>, <getter>) function that indicated a

getter to be invoked on a request for a not own property of the object. If a request for a not own property of <object> is received <getter> is called

with this set to the receiver and the only argument set to the requested property.

My proposed Object.guard function could just be accomplished by something like

Object.notOwnPropertyValue(myObject, (prop) => {throw Error("Bad

property: " + prop);})

For the purposes of catching bad property references, this is better than my previous proposal because it eliminates the need for [[Get]] (P, Receiver) to maintain a guard barrier state as it works it way down the prototype chain. Instead, if someone wanted to not throw for properties on the prototype chain, the notOwnPropertyValue getter could itself check for the property in the receiver's prototype chain:

Object.notOwnPropertyValue( myObject, (prop) => { if (prop in Object.getPrototypeOf(myObject) return Object.getPrototypeOf(myObject)[prop]; throw Error("Bad property: " + prop); } }

Obviously this could be done more tidily and efficiently but hopefully the point is clear.

A simple alternative use (to a bad property reference catcher) of this capability would be something like

let counts = {}; Object.notOwnPropertyValue(counts, () => 0); someStringArray.forEach((s) => counts[s]++;);

Note that I suspect for most purposes one would set Object.notOwnPropertyValue on a prototype so there'd be no cost to getting a property off any prototypes until a property has not been found yet when we get to a prototype with Object.notOwnPropertyValue set. So for my purposes, I'd create some Guard (my own class) object that would be just above Object in the prototype chain of most of my classes that would throw on an invalid property reference (my choice whether or not to allow Object.prototype properties to be accessed via property accessors on the Guard class objects).

I believe this would be relatively simple to implement and, beyond the definition of Object.notOwnPropertyValue, would require only a minor change to the [[Get]] (P, Receiver) description in the spec:

  1. Assert: IsPropertyKey(P) is true.

  2. Let desc be O.[GetOwnProperty].

  3. ReturnIfAbrupt(desc).

  4. If desc is undefined, then Insert 1 =>. Let getter be O.[[GetNotOwnProperty]]. Insert 2 =>. If getter is not undefined return Call(getter, Receiver, P)

    a. Let parent be O.[GetPrototypeOf]. b. ReturnIfAbrupt(parent). c. If parent is null, return undefined. d. Return parent.[[Get]](P, Receiver).

  5. If IsDataDescriptor(desc) is true, return desc.[[Value]].

  6. Otherwise, IsAccessorDescriptor(desc) must be true so, let getter be desc.[[Get]].

  7. If getter is undefined, return undefined.

  8. Return Call(getter, Receiver).

An alternative would allow argument 1 of Object.notOwnPropertyValue to be a non-function value in which case it would simply be returned rather than called. In the weird case where you want the result of a not own property reference to be a function, you'd have to define a getter that returns the function. Some sort of formal memoization support would, of course, obviate the need for a non-function not own property value. So maybe the function described here should be called Object.notOwnPropertyGetter.

Implementation could be accomplished by having a slot in every object for a notOwnPropertyValue getter or by a bit indicating that there is indeed such a getter and then a hidden Symbol property that references the getter. The latter means that the cost of this feature is one bit per simple object and a bit more overhead if the bit is on. Plus, presumably Object.getOwnPropertySymbols would have to be smart enough not to display the hidden Symbol. But, this is an implementation detail.

Finally a big hand wave for now about how one implements the ability to get rid of a not own property getter -- there are a lot of ways this can be accomplished and it's not worth discussing if there's a truck-sized hole in this proposal or if someone tells me that this is the Nth time this feature has been proposed (I did find the Firefox noSuchMethod Object.prototype method). I suspect another response will be to tell me to use a proxy but that would be an insanely heavyweight way of accomplishing such a simple task.

If no one blows a hole in this proposal, I guess I'll figure out how to turn it into a formal proposal so I can be the proud owner of a stage 0 proposal.

Thanks


Alex Kodat

# Michał Wadas (7 years ago)

a) you can enable assertions in code only in development and make operaton noop in production - that's pretty common in C++ and many other languages b) isn't somewhere there proposal to change a bit Proxy semantics to improve performance and simplify implementation? c) would be property access to garderoby objects ever bottleneck in your application?

# Alex Kodat (7 years ago)

Head slap. The following does what I want with essentially zero overhead (at least with V8):

let handler = { get: (target, prop) => { if (prop in target) return target[prop]; if (typeof prop == "symbol") return target[prop]; if (prop == "inspect") return; throw Error("Bad property: " + prop); } }

function Guard() {} Guard.prototype = new Proxy(Object.freeze({}), handler);

class Foo extends Guard {}

let bar = new Foo; bar.a = 0; bar.b = 1; bar.c = 1;

for (let i = 0; i < 1000000; i++) { bar.a = bar.b; bar.b = bar.c; bar.c = bar.c + i; } bar.z;

That last bar.z throws.

So never mind. Sorry


Alex Kodat

From: Michał Wadas [mailto:michalwadas at gmail.com] Sent: Thursday, September 7, 2017 6:59 PM To: Alex Kodat <alexkodat at gmail.com>

Cc: es-discuss at mozilla.org Subject: Re: Not own property getters

a) you can enable assertions in code only in development and make operaton noop in production - that's pretty common in C++ and many other languages b) isn't somewhere there proposal to change a bit Proxy semantics to improve performance and simplify implementation? c) would be property access to garderoby objects ever bottleneck in your application?

On Fri, 8 Sep 2017 at 01:25, Alex Kodat <mailto:alexkodat at gmail.com> wrote:

If I run the following:

let foo = {a: 0, b: 1, c:1}; let bar = ( new Proxy( foo, {get: (target, prop) => { if (prop in target) return target[prop]; if (typeof prop == "symbol") return target[prop]; if (prop == "inspect") return; if (prop == "toJSON") return; throw Error("Bad property: " + prop); } } ) ); // bar = foo;

for (let i = 0; i < 1000000; i++) { bar.a = bar.b; bar.b = bar.c; bar.c = bar.c + i; }

with the bar = foo assignment above commented out (so using a proxy) and not commented out (so direct object access) and V8 (Chrome), SpiderMonkey (Firefox), and Chakra (Edge) the difference between proxy and not was about a factor of 300-500 (perhaps unsurprisingly, all the JS engines were close-ish to each other).

While perhaps this can be improved, it’s a lot to ask of an optimizer to detect a proxy and figure out what it's doing to the degree that V8 (and I suspect other browsers) detect that bar.a is always at the same offset in bar and always an integer (as long as bar's shape doesn't change) and so optimize the call to a handful of machine language instructions. Let's say some superstar gets the difference down to a factor of 20 (I suspect that's unlikely). That's still a big price to pay for detecting errors or say automatically returning 0 for an undefined property.


Alex Kodat

From: Michał Wadas [mailto:mailto:michalwadas at gmail.com] Sent: Thursday, September 7, 2017 3:55 PM To: Alex Kodat <mailto:alexkodat at gmail.com>

Cc: mailto:es-discuss at mozilla.org Subject: Re: Not own property getters

Why can't you use proxy for this?

On 7 Sep 2017 10:05 pm, "Alex Kodat" <mailto:mailto:alexkodat at gmail.com> wrote:

In a previous post I had proposed an Object.guard (originally badly named as Object.lock) to make it possible to catch references to non-existent properties in code that uses an object.

While that proposal didn't exactly generate a lot of enthusiasm, I now realize that there would be a better way of accomplished what I had proposed with a more general purpose facility. Specifically, if there were an Object.notOwnPropertyValue(<object>, <getter>) function that indicated a

getter to be invoked on a request for a not own property of the object. If a request for a not own property of <object> is received <getter> is called

with this set to the receiver and the only argument set to the requested property.

My proposed Object.guard function could just be accomplished by something like

Object.notOwnPropertyValue(myObject, (prop) => {throw Error("Bad

property: " + prop);})

For the purposes of catching bad property references, this is better than my previous proposal because it eliminates the need for [[Get]] (P, Receiver) to maintain a guard barrier state as it works it way down the prototype chain. Instead, if someone wanted to not throw for properties on the prototype chain, the notOwnPropertyValue getter could itself check for the property in the receiver's prototype chain:

Object.notOwnPropertyValue( myObject, (prop) => { if (prop in Object.getPrototypeOf(myObject) return Object.getPrototypeOf(myObject)[prop]; throw Error("Bad property: " + prop); } }

Obviously this could be done more tidily and efficiently but hopefully the point is clear.

A simple alternative use (to a bad property reference catcher) of this capability would be something like

let counts = {}; Object.notOwnPropertyValue(counts, () => 0); someStringArray.forEach((s) => counts[s]++;);

Note that I suspect for most purposes one would set Object.notOwnPropertyValue on a prototype so there'd be no cost to getting a property off any prototypes until a property has not been found yet when we get to a prototype with Object.notOwnPropertyValue set. So for my purposes, I'd create some Guard (my own class) object that would be just above Object in the prototype chain of most of my classes that would throw on an invalid property reference (my choice whether or not to allow Object.prototype properties to be accessed via property accessors on the Guard class objects).

I believe this would be relatively simple to implement and, beyond the definition of Object.notOwnPropertyValue, would require only a minor change to the [[Get]] (P, Receiver) description in the spec:

  1. Assert: IsPropertyKey(P) is true.

  2. Let desc be O.[GetOwnProperty].

  3. ReturnIfAbrupt(desc).

  4. If desc is undefined, then Insert 1 =>. Let getter be O.[[GetNotOwnProperty]]. Insert 2 =>. If getter is not undefined return Call(getter, Receiver, P)

    a. Let parent be O.[GetPrototypeOf]. b. ReturnIfAbrupt(parent). c. If parent is null, return undefined. d. Return parent.[[Get]](P, Receiver).

  5. If IsDataDescriptor(desc) is true, return desc.[[Value]].

  6. Otherwise, IsAccessorDescriptor(desc) must be true so, let getter be desc.[[Get]].

  7. If getter is undefined, return undefined.

  8. Return Call(getter, Receiver).

An alternative would allow argument 1 of Object.notOwnPropertyValue to be a non-function value in which case it would simply be returned rather than called. In the weird case where you want the result of a not own property reference to be a function, you'd have to define a getter that returns the function. Some sort of formal memoization support would, of course, obviate the need for a non-function not own property value. So maybe the function described here should be called Object.notOwnPropertyGetter.

Implementation could be accomplished by having a slot in every object for a notOwnPropertyValue getter or by a bit indicating that there is indeed such a getter and then a hidden Symbol property that references the getter. The latter means that the cost of this feature is one bit per simple object and a bit more overhead if the bit is on. Plus, presumably Object.getOwnPropertySymbols would have to be smart enough not to display the hidden Symbol. But, this is an implementation detail.

Finally a big hand wave for now about how one implements the ability to get rid of a not own property getter -- there are a lot of ways this can be accomplished and it's not worth discussing if there's a truck-sized hole in this proposal or if someone tells me that this is the Nth time this feature has been proposed (I did find the Firefox noSuchMethod Object.prototype method). I suspect another response will be to tell me to use a proxy but that would be an insanely heavyweight way of accomplishing such a simple task.

If no one blows a hole in this proposal, I guess I'll figure out how to turn it into a formal proposal so I can be the proud owner of a stage 0 proposal.

Thanks


Alex Kodat

# T.J. Crowder (7 years ago)

On Fri, Sep 8, 2017 at 2:28 AM, Alex Kodat <alexkodat at gmail.com> wrote:

Head slap. The following does what I want with essentially zero overhead (at least with V8)...

:-) Clever solution for situations where you can't detect these statically in advance, nice one.

You can turn it up to 11 by avoiding hitting the proxy for the Object.property properties, by making the base guard prototype derive from your proxy and put the Object.property features on it. That way, hasOwnProperty, valueOf, etc. aren't impacted by passing through the proxy. (See my Guarded below.) jsperf.com/throw-on-missing-property-scenarios

You'll also want to handle toJSON and other spec-defined optional properties or properties implementations commonly look for outside spec (is that what your inspect property is?). And set constructor.

function Guarded() {
}
Guarded.prototype = Object.create(new Proxy(Object.freeze(Object.create(null)),
{
  get: (target, prop) => {
    if (prop === "toJSON" || prop === "inspect") {
        return undefined;
    }
    throw Error("Bad property: " +  prop);
  }
}));
Object.defineProperties(Guarded.prototype, Object.getOwnPropertyDescriptors(
Object.prototype));
Object.defineProperty(Guarded.prototype, "constructor", {
    value: Guarded,
    configurable: true
});

class Foo extends Guarded {}

-- T.J. Crowder

# Alex Kodat (7 years ago)

Like many clever solutions, it's been done before: exploringjs.com/es6/ch_proxies.html#sec_proxy-use-cases (in 28.4.2). A co-worker found this after we discussed implementing a guard class for our code. So triple apologies for my postings.

Also good idea on adding the extra level of prototype to the guard class. FWIW, inspect and toJSON could be added to Guarded.prototype (with value undefined, of course) to avoid going through the proxy for the inspect (a Node thing) and toJSON probes. The might be some Symbols you want to add too though looking at the list of standard probed symbols doesn't suggest any compelling ones. Maybe Symbol.toPrimitive?


Alex Kodat

From: T.J. Crowder [mailto:tj.crowder at farsightsoftware.com] Sent: Friday, September 8, 2017 2:51 AM To: Alex Kodat <alexkodat at gmail.com>

Cc: es-discuss at mozilla.org Subject: Re: Not own property getters

On Fri, Sep 8, 2017 at 2:28 AM, Alex Kodat <mailto:alexkodat at gmail.com> wrote:

Head slap. The following does what I want with essentially zero overhead (at least with V8)...

:-) Clever solution for situations where you can't detect these statically in advance, nice one.

You can turn it up to 11 by avoiding hitting the proxy for the Object.property properties, by making the base guard prototype derive from your proxy and put the Object.property features on it. That way, hasOwnProperty, valueOf, etc. aren't impacted by passing through the proxy. (See my Guarded below.) jsperf.com/throw-on-missing-property-scenarios

You'll also want to handle toJSON and other spec-defined optional properties or properties implementations commonly look for outside spec (is that what your inspect property is?). And set constructor.

function Guarded() {
}
Guarded.prototype = Object.create(new Proxy(Object.freeze(Object.create(null)), {
  get: (target, prop) => {
    if (prop === "toJSON" || prop === "inspect") {
        return undefined;
    }
    throw Error("Bad property: " +  prop);
  }
}));
Object.defineProperties(Guarded.prototype, Object.getOwnPropertyDescriptors(Object.prototype));
Object.defineProperty(Guarded.prototype, "constructor", {
    value: Guarded,
    configurable: true
});

class Foo extends Guarded {}

-- T.J. Crowder

# T.J. Crowder (7 years ago)

On Fri, Sep 8, 2017 at 2:52 PM, Alex Kodat <alexkodat at gmail.com> wrote:

FWIW, inspect and toJSON could be added to Guarded.prototype (with value undefined, of course)...

True, but then in would be misleading... :-) (Well, not misleading, because the object would have those properties. Just atypical.)

-- T.J. Crowder