Not own property getters

Alex Kodat alexkodat at gmail.com
Thu Sep 7 20:05:22 UTC 2017


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




More information about the es-discuss mailing list