9

If you have an generator like,

function* f () {
  // Before stuff.
  let a = yield 1;
  let b = yield 2;
  return [a,b];
}

And, then run

var g = f();
// this question is over this value.
g.next(123); // returns: { value: 1, done: false }
g.next(456); // returns: { value: 2, done: false }
g.next(); // returns: { value: [ 456, undefined ], done: true }

The first call to .next() to set a to 123 and the second call to set b to 456, however at the last call to .next() this is return,

{ value: [ 456, undefined ], done: true }

Does the argument in the first call to g.next get lost? What happens to them? Using the above example, how do I set a?

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
Evan Carroll
  • 78,363
  • 46
  • 261
  • 468
  • Duplicate of http://stackoverflow.com/questions/20977379/javascript-yield-what-happens-to-the-arguments-of-the-first-call-next – Loamhoof Jan 22 '14 at 10:56
  • Possible duplicate of [Where argument of first next() call goes?](http://stackoverflow.com/questions/32446723/where-argument-of-first-next-call-goes) – Bergi Mar 30 '16 at 17:32
  • 1
    In simple words ; when we pass argument to next(), it replaces previous yield expression return value with the one we provided.Because it is your first execution of function value 123 is simply discarded. – erhan355 Nov 19 '19 at 11:30

3 Answers3

5

Try:

var g = f();
// this question is over this value.
g.next(); // returns: { value: 1, done: false }
g.next(123); // returns: { value: 2, done: false }
g.next(456); // returns: { value: [123, 456], done: true }
LJHarb
  • 32,486
  • 2
  • 32
  • 38
  • 1
    So the arguments to the first .next() get lost to the ether? That's confusing... why not simply run the first .next() when the call is put out to `var g = f()` why not as part of the IteratorConstructor call it once? When would you ever create a Iterator and not call .next() to get to the first yield? – Evan Carroll Jan 22 '14 at 03:09
  • It looks like the first "next" starts the generator, and you're supposed to use "send" to pass in values afterwards, but "next(foo)" is a shortcut to send a value in. You might not want to actually start executing the generator code right away - the first .next() gives you that control. – LJHarb Jan 22 '14 at 03:11
  • That may very well be true but what's the advantage to *not* executing the generator code right away, and just getting an iterator? Is there a use case where that is handy? And, normally would I be able to `.send()` something to the generator before the `.next()` call? – Evan Carroll Jan 22 '14 at 03:22
  • You might not want to start executing code right away (starting the generator is akin to invoking the function) - this way, the choice is up to you, instead of being imposed by the spec. – LJHarb Jan 22 '14 at 05:12
  • @LJHarb but you cannot do something (with native generators) to disallow misusing the generator somewhere (like by throwing or logging when first next was called with wrong value), this may lead to bugs or performance problems in the code – 4esn0k May 02 '21 at 12:38
  • @LJHarb people say in Python the first call throws an exception when there is an argument – 4esn0k Jun 27 '21 at 08:52
3

Values passed into the first 'next()' call are ignored. Look at the last test (line 34) on this ES6 TDD Coding Kata

For those confused on how a & b are getting set, it might be a good idea to look at the "Advanced Generators" section of Iterators & Generators

Eric Carlson
  • 129
  • 1
  • 4
2

From MDN Iterators and generators.

A value passed to next() will be treated as the result of the last yield expression that paused the generator.

Answers:

Does the argument in the first call to g.next get lost?

Since there is no last yield expression that paused the generator on the first call this value is essentially ignored. You can read more in the ECMAScript 2015 Language Specification.

What happens to them?

On subsequent calls of next() the value passed will be used as the return value of the last yield expression that paused the generator.

Using the above example, how do I set a?

You can do as LJHarb suggested.

"use strict";

let f = function*() {
 let a = yield 1;
 let b = yield 2;
 return [a, b];
};

let g = f();

document.querySelector("#log_1").innerHTML = JSON.stringify(g.next());
document.querySelector("#log_2").innerHTML = JSON.stringify(g.next(123));
document.querySelector("#log_3").innerHTML = JSON.stringify(g.next(456));
<div id="log_1"></div>
<div id="log_2"></div>
<div id="log_3"></div>
Community
  • 1
  • 1
coderfin
  • 1,708
  • 19
  • 24