-
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: re-use IteratorResult objects in some iterator helpers #3489
Conversation
62486f2
to
fde82f1
Compare
Why do you consider this to only be bad for the .value getter and not for the .done getter, which would be double-triggered by all those methods? |
I think an expensive value getter is more likely than an expensive done getter. |
@nicolo-ribaudo Also, someone might be surprised that the resulting iterator yields values for which the predicate would return edit: I've added a slide to the upcoming presentation covering interactions with getters. |
@anba Do you have an opinion on this change? |
This change is possibly difficult to implement for JSC and SM, because both use self-hosted JS for their implementation and the proposed changes can't be easily implemented in JS. ( I guess this also applies to tc39/proposal-iterator-sequencing#18. |
Do you mean that they can't be easily implemented in JS at all, or do you mean using generators in JS? It seems manual iteration in JS should work fine.
I'm open to also requiring the final |
Ping @anba. It'd be great to have your feedback on the above points before plenary next week. |
When using generators. It's probably less of a problem when using normal functions instead of generators, but then it's necessary to duplicate the complete generator state machinery.
I'm not sure about the performance impact when avoiding a single object allocation (per iteration). Local testing showed mixed results, but it's a bit difficult to estimate general performance changes, because I was only testing on SpiderMonkey. Getting results for a possible performance improvement is going to be difficult anyway, because:
For example let's see what will change for for (var value of allowContentIterWithNext(iterator, nextMethod)) {
if (remaining-- <= 0) {
yield value;
}
}
function allowContentIterWithNext(iterator, nextMethod) {
return {
[Symbol.iterator]() {
return this;
},
next() {
return nextMethod.call(iterator);
},
return() {
// Elided for simplicity.
},
};
} Rewriting the function iteratorNext() {
while (remaining > 0) {
var result = callContentFunction(nextMethod, iterator);
if (!IsObject(result)) {
ThrowTypeError(JSMSG_ITER_METHOD_RETURNED_PRIMITIVE, "next");
}
if (result.done) {
return {done: true, value: undefined};
}
remaining -= 1;
}
return callContentFunction(nextMethod, iterator);
}
yield* allowContentIterWithNext(iterator, iteratorNext); Changes:
|
At plenary today, we have decided not to do this, setting precedent for other helpers on |
This re-uses IteratorResult objects when it's possible to just pass the object through. There are currently 3 cases of this:
take
/drop
/filter
. See related PR for the iterator sequencing proposal, which also has this opportunity: tc39/proposal-iterator-sequencing#18I actually don't like doing this for
filter
sincefilter
observes the value, which would mean triggering a value getter both for filtering and by the eventual consumer.