-
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
Editorial: Return an iterator *record* for for...in heads #1969
Conversation
I would regard this as editorial, since the spec is nonsensical as written and the intent is clear. My preferred fix would be to make |
This has come up many times before, but I've never really felt like there was a consistent answer. The spec as written is possible to implement, although following it results in obviously unintended behavior—is fixing that normative? CONTRIBUTING.md implies so, as did my most recent conversation on the topic (cf. #1608 (comment) ).
I like the current form of this fix because it makes clear that every branch of ForIn/OfHeadEvaluation returns a result of the same shape (an iterator Record produced by GetIterator). But if your preference is still different, are you asking for the use of GetIterator to move into EnumerateObjectProperties, or for it to be eliminated? The latter appears quite challenging to me, because EnumerateObjectProperties is defined in terms of ECMAScript values rather than specification types and that seems like a good thing for ForIn/OfHeadEvaluation (whose other ["of"] branches use GetIterator directly on the ECMAScript expression result). |
Is it? As written, evaluating
My preference would be to just note that at the top of
Eliminated, though I guess you're right that this would be challenging and may not be worth it. I mostly dislike using Actually, now that I read closer, I think |
Hmm, interesting. That's not covered in general, but is covered in non-exotic cases by requiring the result to "behave as would the iterator given by CreateForInIterator" (which has inherits a Symbol.iterator property from %IteratorPrototype%). But it also seems to me that GetIterator is observable for that very reason, because it looks up and calls the Symbol.iterator method—and only engine262 exhibits that for for-in, which seems like a bug: $ eshost -sx '
const getP = Object.getPrototypeOf;
const IteratorPrototype = getP(getP([][Symbol.iterator]()));
const iteratorMethod = IteratorPrototype[Symbol.iterator];
IteratorPrototype[Symbol.iterator] = function spy( ...args ) {
print("[Symbol.iterator]", this, ...args);
return iteratorMethod.apply(this, args);
};
for(let v of (function*(){yield "a"})()) print(v, "of Iterable");
for(let v in {a:0}) print(v, "in object");
'
#### ChakraCore, JavaScriptCore, Moddable XS, QuickJS, SpiderMonkey, V8
[Symbol.iterator] [object Generator]
a of Iterable
a in object
#### engine262
[Symbol.iterator] [object Generator]
a of Iterable
[Symbol.iterator] [object Object]
a in object So I guess changes are needed regarding EnumerateObjectProperties, but I'd prefer to minimize them by just requiring the returned iterator to iterable by means of a Symbol.iterator property matching the original value of %IteratorPrototype%[ @@iterator ]. |
The smallest sensible change would be to change
This avoids introducing a new "iterable" layer of indirection. I would prefer to minimize the extent to which we perform computation on spec-fictional objects, as a rule. |
@gibson042 nice catch 😅 |
I think this problem is equal to how we do |
@bakkot I like that. Updated. |
I'm still going to mark this as editorial because the spec is unimplementable as written (and the intent is clear). |
tbh, i think i prefer the GetIterator version (with ! if it can’t actually throw), so there’s a single place where the iterator Record is created :-/ |
Using |
Not observably tho, right? In this case, the indirection to me is a good thing, because GetIterator is something that I consider widely understood. |
Not observably in the sense that we usually mean it, no.
|
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.
lgtm
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.
I don't love it, but at least it's correct now.
dfec7b8
to
5e722af
Compare
ForIn/OfBodyEvaluation expects an iterator Record of the sort returned by GetIterator (with [[Iterator]] and [[NextMethod]] slots) from ForIn/OfHeadEvaluation, but the
for...in
("enumerate") branch was instead returning an Iterator object (with anext
method) from EnumerateObjectProperties. This corrects the mistake by passing that object to GetIterator.