8

I was expecting 4 to be part of the sequence array, so why is it skipped?

function* generate() {
 yield 1;
 yield 2;
 yield 3;
 return 4
}
let sequence = [...generate()];
console.log(sequence); // 1, 2, 3

Patrick Roberts
52.4k10 gold badges120 silver badges166 bronze badges
asked Jan 24, 2021 at 13:20
11
  • 2
    @MisterJojo there is, but it finishes the generator. Commented Jan 24, 2021 at 13:27
  • 1
    @MisterJojo the return statement is marking the generator end with the attribute done:true Commented Jan 24, 2021 at 13:27
  • 1
    yes all of the iterators do not use the done:true. for (x of genarator()) will also not get it. Commented Jan 24, 2021 at 13:39
  • 2
    The done flag is checked in a way that ignores the value returned. When done is true, iteration is complete. Commented Jan 24, 2021 at 13:41
  • 3
    Read developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/… "Done: This is true if the last value in the sequence has already been consumed." Commented Jan 24, 2021 at 13:41

1 Answer 1

6

The return value of a generator function is not considered part of the sequence. It is returned from the last .next() call as {done: true, value:...}, where done: true implies that the sequence was completed and .next() should not be called again.

Why is that so, why couldn't we just yield the last value with the done flag set to true? Because then we could not represent an empty sequence with an iterator - the first .next() call would already lead to at least one value.1

So usually, generator functions do not return anything (but undefined), and all sequence values are yielded with the same syntax - there is no weird special syntax for the last value2:

function* generate() {
 yield 1;
 yield 2;
 yield 3;
 yield 4;
}

1: Other languages do this differently. There, iterators have a separate .hasNext() method that is called before .next(), or their .next() method either returns a value or throws a StopIteration exception. They don't have any "final value".
2: Having to know beforehand that a value is that last and using return instead of yield for it would make the logic for dynamically generated sequences much more complicated.

answered Jan 24, 2021 at 14:16
Sign up to request clarification or add additional context in comments.

3 Comments

This happens if you combine a function that must return a value with an ambiguous computation (e.g. []). You are stuck with a meaningless return value. The iterator protocol has no formal foundation. It is poorly designed and ignores decades of CS.
Best part of the answer is explaining why this approach allows us to represent an empty sequence, as opposed to the alternative that the question implies. Also in response to your footnote, you can think of next() as a sort of std::optional where done is !has_value.
@scriptum I understand the IteratorResult type to be a poor man's Maybe for the usual iterator use case - you either have {done: false, value: ...} or {done: true}. Also, generator functions additionally serve as coroutines in JS, and for them the final value is rather useful.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.