Proposal: Reflecting on non-string property names
allen at wirfs-brock.com
Sun Dec 2 10:05:37 PST 2012
On Dec 2, 2012, at 8:44 AM, Tom Van Cutsem wrote:
> 2012/12/1 Allen Wirfs-Brock <allen at wirfs-brock.com>
> 1) In ES6 property keys are no longer limited to string values, we now also have keys that are Symbols.
> 2) Some meta-programming tasks will requires a way to reflectively obtain a list of all public property keys.
> 3) The existing reflection APIs for property keys (Object.getOwnPropertyNames and Object.keys) only return string values and we don't want to break existing clients of those functions by returning non-string values.
> 1) Object.getOwnPropertyNames and Object.keys remain unchanged. They only return a string property key values.
> 2) Reflect.ownKeys(obj) is a new reflection function that returns an iterator. The iterator produces the keys of all public own properties of the object pass as an argument. This includes both string and Symbol key values. A property whose key is a private Symbol is not a public property and its key is not returned by the ownKeys iterator.
> 3) The [[OwnPropertyKeys]] internal method is defined to return an iterator with the same definition as used for Reflect.ownKeys. (Reflect.ownKeys is implemented as a call to this internal method). [[OwnPropertyKeys]] replaces the like-named internal method in the current spec. draft and also replaces the [[GetOwnPropertyNames]] internal method used in the wiki Proxy proposals.
> 4) ownKeys is the corresponding Proxy trap. The getOwnPropertyNames trap is removed.
> 5) Object.keys and Object.getOwnPropertyNames are respecified in terms of [[OwnPropertyKeys]]. They internally drain the iterator and continue to return arrays of strings.
> Any objections?
> Sounds good.
> We probably still need to clear up the discussion on invariants for [[OwnPropertyKeys]] on a non-extensible proxy. I don't remember if we reached a consensus on that.
No, and I didn't address it in my proposal above.
I still think making [[OwnPropertyKeys]] produce an iterator makes sense. But it probably means we have to change how we think about the its invariants as we can't necessarily check all of the values such an iterator may yield before returning it from the Proxy implementation of [[OwnPropertyKeys]]. We can however have that [[OwnPropertyKeys]] wrap the iterator returned by the ownKeys trap with another iterator that does an invariant check of the individual values returned by the trap provided iterator.
The first issue, with that approach, is whether such delayed invariant checking is acceptable. For example, returning a key that doesn't exist in a frozen target would throw on the iterator.next call that would return that key rather than when calling Object.getOwnPropertyKeys. (However, Object.getOwnProperyNames/keys would still appear to throw immediately, because they drain the iterator). This delayed checking seems ok to me, but you probably need to think about it from the perspective of membranes and similar Proxy use cases.
One difference with a deferred invariant check is that is to obtain a own property keys iterator before a Proxy object/target is frozen but not check its values until after it is frozen. In this case, the keys produced by the iterator would not necessarily meet the target own property invariants of a frozen object. However, I don't see that is significantly different from the current array valued calls which also can produce key values that may no longer be valid after the objet is frozen.
Deferred checking can easily enforce that a "new property key" isn't return returned (from the iterator) for a frozen object. It can also determine that all own property keys are returned for a frozen object (immediately before throwing IterationComplete check if the number of keys already yielded equals the number of own properties of the target, if not throw to indicate the invariant violation).
What isn't so easily do is make sure that for non-frozen objects all non-configurable property keys are returned. To do this would probably require accumulating every yielded key and then checking that list against the actual target properties immediately before StopIteration.
This makes be think that this final invariant perhaps isn't so important, even for the present non-iterator based definition of getOwnPropetyNames.
Basically for non-frozen/sealed objects any point in time list of property keys may become stale before it is used. It may include keys that are no longer used and may miss keys that are now used. Any inclusion decisions based upon the configurability of individual properties may no longer be valid.
We've talked before about the need of a reliable property list for "deep freezing" objects. In seems for situations like that you would want to separately determine if the object is sealed/frozen before calling Reflect.ownKeys. If it is frozen/sealed, you can depend upon the results. If not, that final invariant (and probably the others) doesn't really guarantee much.
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the es-discuss