[[OwnPropertyKeys]]

# Jason Orendorff (7 years ago)

It looks like [[OwnPropertyKeys]] is defined to return an iterator. But the ordinary [[OwnPropertyKeys]] method produces the List of keys to be iterated eagerly, and pretty every place that calls the method immediately consumes the entire iterator. So there is no actual laziness.

This is weird. I think it would be clearer for [[OwnPropertyKeys]] to return a List of PropertyKeys.

Except for proxies, this doesn't change behavior. Here are the changes needed to implement this:

  • In 9.1.12, the ordinary object [[OwnPropertyKeys]] method, change step 3 to just say "Return keys." instead of "Return CreateListIterator(keys)."

  • In 9.5.12, the Proxy [[OwnPropertyKeys]] method, treat the return value as an iterable (not an iterator) and convert it to a List of PropertyKeys using IteratorStep, IteratorValue, and ToPropertyKey. Change the NOTE to describe the new invariant.

  • In 19.1.2.1 Object.assign, 19.1.2.8.1 GetOwnPropertyKeys, 19.1.2.14 Object.keys, and 19.1.2.15.1 MixinProperties, drop the IteratorStep boilerplate.

  • In 26.1.10 Reflect.ownKeys(), convert the result of calling [[OwnPropertyKeys]] to an Array using CreateArrayFromList.

Note that 7.3.10 SetIntegrityLevel and 7.3.11 TestIntegrityLevel already assume that [[OwnPropertyKeys]] returns a List, as proposed.

# Nick Krempel (7 years ago)

You mean I won't be able to create an object with infinitely many properties anymore? ;-(

# Allen Wirfs-Brock (7 years ago)

I'm working with TomVC right now on revising these internal methods. More on that soon.

One possible advantage of using an Iterator is that large dense indexable objects such as typed arrays, strings, or similar abstractions defined using a proxy don't have to instantiate an Array containing huge numbers of element indices.

Also we have talk about, the future addition of user land iterator valued functions such as keys, ownKeys, etc. or the possibility of frameworks providing such functions. The internal methods. The MOP defined by the internal methods should provide a stable foundation for such future extensions.

# Tom Van Cutsem (7 years ago)

As currently specified, [[OwnPropertyKeys]] doesn't have any particular invariants on the values it generates from the returned iterator.

Mark and I proposed to reintroduce [[GetOwnPropertyNames]] as a separate internal method, which would return an array rather than an iterator, but which would also be required to return at least the names (symbols or strings) of all non-configurable properties. The switch to an array return value is motivated partly by the reasons Jason stated, but also because actually checking the invariant requires exhausting the iterator anyway.

[[OwnPropertyKeys]] would continue to return an iterator (or iterable , as Jason suggests, which seems to make more sense), but there would be no invariants on its generated values.

[[GetOwnPropertyNames]] would be the reliable way of querying an object for its own properties, and would be used at least by Object.getOwnPropertyNames and the abstract operations used by Object.{freeze,isFrozen,seal,isSealed}, so that the result of these operations can in turn be made reliable.

[[OwnPropertyKeys]] can be used for all other operations that don't need the invariant that all non-configurable properties should be listed/generated.

Cheers, Tom

2013/12/6 Allen Wirfs-Brock <allen at wirfs-brock.com>

# Andrea Giammarchi (7 years ago)

+1 also to not use iteraros by default when the use case never needed one

# Mark S. Miller (7 years ago)

On Sat, Dec 7, 2013 at 10:45 AM, Tom Van Cutsem <tomvc.be at gmail.com> wrote:

As currently specified, [[OwnPropertyKeys]] doesn't have any particular invariants on the values it generates from the returned iterator.

Mark and I proposed to reintroduce [[GetOwnPropertyNames]] as a separate internal method, which would return an array rather than an iterator, but which would also be required to return at least the names (symbols or strings) of all non-configurable properties. The switch to an array return value is motivated partly by the reasons Jason stated, but also because actually checking the invariant requires exhausting the iterator anyway.

[[OwnPropertyKeys]] would continue to return an iterator (or iterable , as Jason suggests, which seems to make more sense), but there would be no invariants on its generated values.

[[GetOwnPropertyNames]] would be the reliable way of querying an object for its own properties, and would be used at least by Object.getOwnPropertyNames and the abstract operations used by Object.{freeze,isFrozen,seal,isSealed}, so that the result of these operations can in turn be made reliable.

Hi Tom, when we talked I think we overlooked something crucial. The requirement as stated, "return at least the names (symbols or strings) of all non-configurable properties", is not actually sufficient for freeze, isFrozen, etc. We must additionally state that, if the object has been observed to be non-extensible, then it may not afterwards claim to have any own properties not observed by [[GetOwnPropertyNames]]. Without this additional requirement, a non-extensible object can "hide" non-configurable own properties from freeze, isFrozen, etc.

# Mark S. Miller (7 years ago)

On Sat, Dec 7, 2013 at 11:26 AM, Mark S. Miller <erights at google.com> wrote:

Without this additional requirement, a non-extensible object can "hide" non-configurable own properties from freeze, isFrozen, etc.

Should be: ...can "hide" configurable own properties...

# Allen Wirfs-Brock (7 years ago)

On Dec 7, 2013, at 11:26 AM, Mark S. Miller wrote:

Hi Tom, when we talked I think we overlooked something crucial. The requirement as stated, "return at least the names (symbols or strings) of all non-configurable properties", is not actually sufficient for freeze, isFrozen, etc. We must additionally state that, if the object has been observed to be non-extensible, then it may not afterwards claim to have any own properties not observed by [[GetOwnPropertyNames]]. Without this additional requirement, a non-extensible object can "hide" non-configurable own properties from freeze, isFrozen, etc.

If the primary motivation is to ensure the integrity of freeze (and seal??) then a [[Freeze]] mop operations seems like a better solution to me.

BTW, this seems like old territory, at one time we had a [[SetIntegrity]] mop operation that could be used to implement both Object.freeze and Object.seal. Why did we get rid of it?

# Mark S. Miller (7 years ago)

On Sat, Dec 7, 2013 at 11:41 AM, Allen Wirfs-Brock <allen at wirfs-brock.com>wrote:

If the primary motivation is to ensure the integrity of freeze (and seal??) then a [[Freeze]] mop operations seems like a better solution to me.

Actually, freeze and seal are examples. As another example, the SES startup uses Object.getOwnPropertyNames to do a thorough walk of the initial primordials, aside from the global object, and remove anything not on its whitelist. If it does find something not on its whitelist that it can't delete and doesn't know to be safe for other reasons, then it declares that this platform cannot be made SES-safe. That's why bugzilla.mozilla.org/show_bug.cgi?id=724768#c8 was such a problem for us. What the combination of non-extensible and getOwnProperties gives us is confidence that there's nothing there beyond what we see.

BTW, this seems like old territory, at one time we had a [[SetIntegrity]] mop operation that could be used to implement both Object.freeze and Object.seal. Why did we get rid of it?

I remember I was for a time in favor of [[SetIntegrity]], and made arguments in support of it. However, it was additional semantic state that was approximately redundant with the state already there, and could get out of sync with it. If now were earlier in the ES6 cycle I would be open to reconsidering it. But it raised so many open questions that I don't think we should reopen it unless something is broken with the current plan. If we do reopen [[SetIntegrity]], we should decide to slip the schedule.

# Brendan Eich (7 years ago)

Mark S. Miller wrote:

I remember I was for a time in favor of [[SetIntegrity]], and made arguments in support of it. However, it was additional semantic state that was approximately redundant with the state already there, and could get out of sync with it. If now were earlier in the ES6 cycle I would be open to reconsidering it. But it raised so many open questions that I don't think we should reopen it unless something is broken with the current plan. If we do reopen [[SetIntegrity]], we should decide to slip the schedule.

See, e.g.,

esdiscuss/2013-February/028854

and

esdiscuss/2013-March/029277

We did not have consensus on per-object Get/SetIntegrity. I don't think we want the redundancy entailed. Implementors I've spoken with do not. This seems a dead snake, so no need to shoot at it.

# Tom Van Cutsem (7 years ago)

2013/12/8 Brendan Eich <brendan at mozilla.com>

We did not have consensus on per-object Get/SetIntegrity. I don't think we want the redundancy entailed. Implementors I've spoken with do not. This seems a dead snake, so no need to shoot at it.

Thanks for digging up those links. Indeed, no need to revisit this. The only requirement is that the abstract algorithms TestIntegrity and SetIntegrity in the current ES6 draft use a reliable internal method for querying the object's own properties (i.e. something like [[GetOwnPropertyNames]] rather than [[OwnPropertyKeys]]).

@Mark: you are right about the additional restriction. W.r.t. invariant checks on proxies, I believe this implies that once a proxy's target is non-extensible, the handler must return from its getOwnPropertyNames trap exactly the set of properties returned from Object.getOwnPropertyNames(target). That is: proxies cannot virtualize the list of properties for non-extensible objects. While this may seem awkward at first, this is precisely the restriction that we need so that Object.freeze and isFrozen remain reliable in the presence of proxies.

# Mark S. Miller (7 years ago)

Agreed