Not own property getters

classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

Not own property getters

Alex Kodat-2
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]](P).
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


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Not own property getters

Michał Wadas
Why can't you use proxy for this? 

On 7 Sep 2017 10:05 pm, "Alex Kodat" <[hidden email]> 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]](P).
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


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

RE: Not own property getters

Alex Kodat-2
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:[hidden email]]
Sent: Thursday, September 7, 2017 3:55 PM
To: Alex Kodat <[hidden email]>
Cc: [hidden email]
Subject: Re: Not own property getters

Why can't you use proxy for this?

On 7 Sep 2017 10:05 pm, "Alex Kodat" <mailto:[hidden email]> 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]](P).
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


_______________________________________________
es-discuss mailing list
mailto:[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Not own property getters

Michał Wadas
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 <[hidden email]> 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:[hidden email]]
Sent: Thursday, September 7, 2017 3:55 PM
To: Alex Kodat <[hidden email]>
Cc: [hidden email]
Subject: Re: Not own property getters

Why can't you use proxy for this?

On 7 Sep 2017 10:05 pm, "Alex Kodat" <mailto:[hidden email]> 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]](P).
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


_______________________________________________
es-discuss mailing list
mailto:[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

RE: Not own property getters

Alex Kodat-2
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:[hidden email]]
Sent: Thursday, September 7, 2017 6:59 PM
To: Alex Kodat <[hidden email]>
Cc: [hidden email]
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:[hidden email]> 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:[hidden email]]
Sent: Thursday, September 7, 2017 3:55 PM
To: Alex Kodat <mailto:[hidden email]>
Cc: mailto:[hidden email]
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:[hidden email]> 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]](P).
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


_______________________________________________
es-discuss mailing list
mailto:mailto:[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Not own property getters

T.J. Crowder-2
On Fri, Sep 8, 2017 at 2:28 AM, Alex Kodat
> 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.)

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`.

```js
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

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

RE: Not own property getters

Alex Kodat-2
Like many clever solutions, it's been done before: http://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:[hidden email]]
Sent: Friday, September 8, 2017 2:51 AM
To: Alex Kodat <[hidden email]>
Cc: [hidden email]
Subject: Re: Not own property getters

On Fri, Sep 8, 2017 at 2:28 AM, Alex Kodat
<mailto:[hidden email]> 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.)
https://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`.

```js
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

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Not own property getters

T.J. Crowder-2
On Fri, Sep 8, 2017 at 2:52 PM, Alex Kodat
> 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

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss