-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Normative: Remove [[Enumerate]] and associated reflective capabilities #367
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1293,17 +1293,6 @@ <h1>Object Internal Methods and Internal Slots</h1> | |
Create or alter the own property, whose key is _propertyKey_, to have the state described by _PropertyDescriptor_. Return *true* if that property was successfully created/updated or *false* if the property could not be created or updated. | ||
</td> | ||
</tr> | ||
<tr> | ||
<td> | ||
[[Enumerate]] | ||
</td> | ||
<td> | ||
()<b>→</b>Object | ||
</td> | ||
<td> | ||
Return an iterator object that produces the keys of the string-keyed enumerable properties of the object. | ||
</td> | ||
</tr> | ||
<tr> | ||
<td> | ||
[[OwnPropertyKeys]] | ||
|
@@ -1504,12 +1493,6 @@ <h2>[[Delete]] ( _P_ )</h2> | |
If P was previously observed to be a non-configurable own data or accessor property of the target, [[Delete]] must return false. | ||
</li> | ||
</ul> | ||
<h2>[[Enumerate]] ( )</h2> | ||
<ul> | ||
<li> | ||
The Type of the return value must be Object. | ||
</li> | ||
</ul> | ||
<h2>[[OwnPropertyKeys]] ( )</h2> | ||
<ul> | ||
<li> | ||
|
@@ -4415,8 +4398,7 @@ <h1>EnumerableOwnNames (_O_)</h1> | |
1. Let _desc_ be ? _O_.[[GetOwnProperty]](_key_). | ||
1. If _desc_ is not *undefined*, then | ||
1. If _desc_.[[Enumerable]] is *true*, append _key_ to _names_. | ||
1. If _O_.[[Enumerate]] is the ordinary object [[Enumerate]] internal method (<emu-xref href="#sec-ordinary-object-internal-methods-and-internal-slots-enumerate"></emu-xref>), then | ||
1. Order the elements of _names_ so they are in the same relative order as would be produced by the Iterator that would be returned if the [[Enumerate]] internal method was invoked on _O_. | ||
1. Order the elements of _names_ so they are in the same relative order as would be produced by the Iterator that would be returned if the EnumerateObjectProperties internal method was invoked with _O_. | ||
1. Return _names_. | ||
</emu-alg> | ||
<emu-note> | ||
|
@@ -6517,39 +6499,6 @@ <h1>[[Delete]] (_P_)</h1> | |
</emu-alg> | ||
</emu-clause> | ||
|
||
<!-- es6num="9.1.11" --> | ||
<emu-clause id="sec-ordinary-object-internal-methods-and-internal-slots-enumerate"> | ||
<h1>[[Enumerate]] ()</h1> | ||
<p>When the [[Enumerate]] internal method of _O_ is called the following steps are taken:</p> | ||
<emu-alg> | ||
1. Return an Iterator object (<emu-xref href="#sec-iterator-interface"></emu-xref>) whose `next` method iterates over all the String-valued keys of enumerable properties of _O_. The Iterator object must inherit from %IteratorPrototype% (<emu-xref href="#sec-%iteratorprototype%-object"></emu-xref>). The mechanics and order of enumerating the properties is not specified but must conform to the rules specified below. | ||
</emu-alg> | ||
<p>The iterator's `next` method processes object properties to determine whether the property key should be returned as an iterator value. Returned property keys do not include keys that are Symbols. Properties of the target object may be deleted during enumeration. A property that is deleted before it is processed by the iterator's `next` method is ignored. If new properties are added to the target object during enumeration, the newly added properties are not guaranteed to be processed in the active enumeration. A property name will be returned by the iterator's `next` method at most once in any enumeration.</p> | ||
<p>Enumerating the properties of the target object includes enumerating properties of its prototype, and the prototype of the prototype, and so on, recursively; but a property of a prototype is not processed if it has the same name as a property that has already been processed by the iterator's `next` method. The values of [[Enumerable]] attributes are not considered when determining if a property of a prototype object has already been processed. The enumerable property names of prototype objects must be obtained as if by invoking the prototype object's [[Enumerate]] internal method. [[Enumerate]] must obtain the own property keys of the target object as if by calling its [[OwnPropertyKeys]] internal method. Property attributes of the target object must be obtained as if by calling its [[GetOwnProperty]] internal method.</p> | ||
<emu-note> | ||
<p>The following is an informative definition of an ECMAScript generator function that conforms to these rules:</p> | ||
<pre><code class="javascript"> | ||
function* enumerate(obj) { | ||
let visited = new Set; | ||
for (let key of Reflect.ownKeys(obj)) { | ||
if (typeof key === "string") { | ||
let desc = Reflect.getOwnPropertyDescriptor(obj, key); | ||
if (desc) { | ||
visited.add(key); | ||
if (desc.enumerable) yield key; | ||
} | ||
} | ||
} | ||
let proto = Reflect.getPrototypeOf(obj) | ||
if (proto === null) return; | ||
for (let protoName of Reflect.enumerate(proto)) { | ||
if (!visited.has(protoName)) yield protoName; | ||
} | ||
} | ||
</code></pre> | ||
</emu-note> | ||
</emu-clause> | ||
|
||
<!-- es6num="9.1.12" --> | ||
<emu-clause id="sec-ordinary-object-internal-methods-and-internal-slots-ownpropertykeys"> | ||
<h1>[[OwnPropertyKeys]] ( )</h1> | ||
|
@@ -8078,16 +8027,6 @@ <h1>[[Delete]] (_P_)</h1> | |
</emu-alg> | ||
</emu-clause> | ||
|
||
<!-- es6num="9.4.6.11" --> | ||
<emu-clause id="sec-module-namespace-exotic-objects-enumerate"> | ||
<h1>[[Enumerate]] ()</h1> | ||
<p>When the [[Enumerate]] internal method of a module namespace exotic object _O_ is called the following steps are taken:</p> | ||
<emu-alg> | ||
1. Let _exports_ be the value of _O_'s [[Exports]] internal slot. | ||
1. Return CreateListIterator(_exports_). | ||
</emu-alg> | ||
</emu-clause> | ||
|
||
<!-- es6num="9.4.6.12" --> | ||
<emu-clause id="sec-module-namespace-exotic-objects-ownpropertykeys"> | ||
<h1>[[OwnPropertyKeys]] ( )</h1> | ||
|
@@ -8231,14 +8170,6 @@ <h1>Proxy Object Internal Methods and Internal Slots</h1> | |
`defineProperty` | ||
</td> | ||
</tr> | ||
<tr> | ||
<td> | ||
[[Enumerate]] | ||
</td> | ||
<td> | ||
`enumerate` | ||
</td> | ||
</tr> | ||
<tr> | ||
<td> | ||
[[OwnPropertyKeys]] | ||
|
@@ -8646,32 +8577,6 @@ <h1>[[Delete]] (_P_)</h1> | |
</emu-note> | ||
</emu-clause> | ||
|
||
<!-- es6num="9.5.11" --> | ||
<emu-clause id="sec-proxy-object-internal-methods-and-internal-slots-enumerate"> | ||
<h1>[[Enumerate]] ()</h1> | ||
<p>When the [[Enumerate]] internal method of a Proxy exotic object _O_ is called the following steps are taken:</p> | ||
<emu-alg> | ||
1. Let _handler_ be the value of the [[ProxyHandler]] internal slot of _O_. | ||
1. If _handler_ is *null*, throw a *TypeError* exception. | ||
1. Assert: Type(_handler_) is Object. | ||
1. Let _target_ be the value of the [[ProxyTarget]] internal slot of _O_. | ||
1. Let _trap_ be ? GetMethod(_handler_, `"enumerate"`). | ||
1. If _trap_ is *undefined*, then | ||
1. Return ? _target_.[[Enumerate]](). | ||
1. Let _trapResult_ be ? Call(_trap_, _handler_, « _target_ »). | ||
1. If Type(_trapResult_) is not Object, throw a *TypeError* exception. | ||
1. Return _trapResult_. | ||
</emu-alg> | ||
<emu-note> | ||
<p>[[Enumerate]] for proxy objects enforces the following invariants:</p> | ||
<ul> | ||
<li> | ||
The result of [[Enumerate]] must be an Object. | ||
</li> | ||
</ul> | ||
</emu-note> | ||
</emu-clause> | ||
|
||
<!-- es6num="9.5.12" --> | ||
<emu-clause id="sec-proxy-object-internal-methods-and-internal-slots-ownpropertykeys"> | ||
<h1>[[OwnPropertyKeys]] ( )</h1> | ||
|
@@ -16008,7 +15913,7 @@ <h1>Runtime Semantics: ForIn/OfHeadEvaluation ( _TDZnames_, _expr_, _iterationKi | |
1. If _exprValue_.[[value]] is *null* or *undefined*, then | ||
1. Return Completion{[[type]]: ~break~, [[value]]: ~empty~, [[target]]: ~empty~}. | ||
1. Let _obj_ be ToObject(_exprValue_). | ||
1. Return ? _obj_.[[Enumerate]](). | ||
1. Return ? EnumerateObjectProperties(_obj_). | ||
1. Else, | ||
1. Assert: _iterationKind_ is ~iterate~. | ||
1. Return ? GetIterator(_exprValue_). | ||
|
@@ -16079,6 +15984,40 @@ <h1>Runtime Semantics: Evaluation</h1> | |
1. Return ? ResolveBinding(_bindingId_). | ||
</emu-alg> | ||
</emu-clause> | ||
|
||
<!-- es6num="9.1.11" --> | ||
<emu-clause id="sec-enumerate-object-properties" aoid="EnumerateObjectProperties"> | ||
<h1>EnumerateObjectProperties (_O_)</h1> | ||
<p>When the abstract operation EnumerateObjectProperties is called with argument _O_, the following steps are taken:</p> | ||
<emu-alg> | ||
1. Assert: Type(_O_) is Object. | ||
1. Return an Iterator object (<emu-xref href="#sec-iterator-interface"></emu-xref>) whose `next` method iterates over all the String-valued keys of enumerable properties of _O_. The Iterator object must inherit from %IteratorPrototype% (<emu-xref href="#sec-%iteratorprototype%-object"></emu-xref>). The mechanics and order of enumerating the properties is not specified but must conform to the rules specified below. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you think it makes sense to define that the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I guess both throw and return should be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And actually the requirement that it MUST inherit from %IteratorPrototype% is kind of bogus since the intention is this isn't observable. Can I simply remove that line? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, you can remove that line. I'd probably also add the note "The Iterator object is never directly accessible to ECMAScript code." to underline that implementations don't actually need to create a JavaScript object. |
||
</emu-alg> | ||
<p>The iterator's `next` method processes object properties to determine whether the property key should be returned as an iterator value. Returned property keys do not include keys that are Symbols. Properties of the target object may be deleted during enumeration. A property that is deleted before it is processed by the iterator's `next` method is ignored. If new properties are added to the target object during enumeration, the newly added properties are not guaranteed to be processed in the active enumeration. A property name will be returned by the iterator's `next` method at most once in any enumeration.</p> | ||
<p>Enumerating the properties of the target object includes enumerating properties of its prototype, and the prototype of the prototype, and so on, recursively; but a property of a prototype is not processed if it has the same name as a property that has already been processed by the iterator's `next` method. The values of [[Enumerable]] attributes are not considered when determining if a property of a prototype object has already been processed. The enumerable property names of prototype objects must be obtained as if by invoking EnumerateObjectProperties passing the prototype object as the argument. EnumerateObjectProperties must obtain the own property keys of the target object as if by calling its [[OwnPropertyKeys]] internal method. Property attributes of the target object must be obtained as if by calling its [[GetOwnProperty]] internal method.</p> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need to change "as if by calling" to "by calling" to properly define the behaviour when enumerating the properties of a proxied object? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure this is necessary, can you expand? The difference between the two seems slight, with the former signaling that the implementation need not actually be a recursive proto-walk, but the result must look like it was a recursive proto-walk. Seems like allowing this for proxies isn't bad as long as the difference isn't observable. Probably missing something. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "as if by calling" was added in https://bugs.ecmascript.org/show_bug.cgi?id=4107, because we need the same set of property names, but we don't want to require to call [[OwnPropertyKeys]] (or [[GetOwnProperty]]). From getify/You-Dont-Know-JS#423 (comment):
The last part ("get those results some other way") is clearly not applicable for proxy objects (and we don't want to mislead implementers to do something other than calling [[OwnPropertyKeys]] on proxies), so it seems wrong to me to leave it in. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok I agree, will remove all as-ifs. Implementations must invoke [[OwnPropertyKeys]] once per object in the prototype chain and [[GetOwnProperty]] once for each property, in some order. |
||
<emu-note> | ||
<p>The following is an informative definition of an ECMAScript generator function that conforms to these rules:</p> | ||
<pre><code class="javascript"> | ||
function* EnumerateObjectProperties(obj) { | ||
let visited = new Set; | ||
for (let key of Reflect.ownKeys(obj)) { | ||
if (typeof key === "string") { | ||
let desc = Reflect.getOwnPropertyDescriptor(obj, key); | ||
if (desc) { | ||
visited.add(key); | ||
if (desc.enumerable) yield key; | ||
} | ||
} | ||
} | ||
let proto = Reflect.getPrototypeOf(obj) | ||
if (proto === null) return; | ||
for (let protoName of EnumerateObjectProperties(proto)) { | ||
if (!visited.has(protoName)) yield protoName; | ||
} | ||
} | ||
</code></pre> | ||
</emu-note> | ||
</emu-clause> | ||
</emu-clause> | ||
</emu-clause> | ||
|
||
|
@@ -35082,16 +35021,6 @@ <h1>Reflect.deleteProperty ( _target_, _propertyKey_ )</h1> | |
</emu-alg> | ||
</emu-clause> | ||
|
||
<!-- es6num="26.1.5" --> | ||
<emu-clause id="sec-reflect.enumerate"> | ||
<h1>Reflect.enumerate ( _target_ )</h1> | ||
<p>When the `enumerate` function is called with argument _target_ the following steps are taken:</p> | ||
<emu-alg> | ||
1. If Type(_target_) is not Object, throw a *TypeError* exception. | ||
1. Return ? _target_.[[Enumerate]](). | ||
</emu-alg> | ||
</emu-clause> | ||
|
||
<!-- es6num="26.1.6" --> | ||
<emu-clause id="sec-reflect.get"> | ||
<h1>Reflect.get ( _target_, _propertyKey_ [ , _receiver_ ])</h1> | ||
|
@@ -35275,8 +35204,9 @@ <h1>[ @@iterator ] ( )</h1> | |
<p>When the @@iterator method is called with no arguments, the following steps are taken:</p> | ||
<emu-alg> | ||
1. Let _N_ be the *this* value. | ||
1. If Type(_N_) is not Object, throw a *TypeError* exception. | ||
1. Return ? _N_.[[Enumerate]](). | ||
1. If _N_ is not a module namespace exotic object, throw a *TypeError* exception. | ||
1. Let _exports_ be the value of _N_'s [[Exports]] internal slot. | ||
1. Return ! CreateListIterator(_N_). | ||
</emu-alg> | ||
<p>The value of the `name` property of this function is `"[Symbol.iterator]"`.</p> | ||
</emu-clause> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the note on the next line (
"<p>The order of elements in the returned list is the same as the enumeration order that is used by a for-in statement.</p>"
but github has trouble showing it and won't let me comment on it) still necessary? It seems implied byEnumerateObjectProperties
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, removed the note.