0

Consider this snippet of code :

function foo(a) {
  console.log("Mul =", a);
  return a * 2;
};

function * process(start) {
  // next() #1
  var result = start;

  console.log("Pre-processing =", result);
  result = yield foo(result);
  // next() #2
  console.log("Process result 1 =", result);
  result = yield foo(result);
  // next() #3
  console.log("Process result 2 =", result);
  result = yield foo(result);
  // next() #4
  console.log("Process result 3 =", result);

  return foo(result);
}

var it = process(1);
console.log("#1");
console.log("Next 1 =", /*#1*/it.next("bar"));
console.log("#2");
console.log("Next 2 =", /*#2*/it.next(3));
console.log("#3");
console.log("Next 3 =", /*#3*/it.next(7));
console.log("#4");
console.log("Next 4 =", /*#4*/it.next(15));

And the output

#1
Pre-processing = 1
Mul = 1
Next 1 = { value: 2, done: false }
#2
Process result 1 = 3
Mul = 3
Next 2 = { value: 6, done: false }
#3
Process result 2 = 7
Mul = 7
Next 3 = { value: 14, done: false }
#4
Process result 3 = 15
Mul = 15
Next 4 = { value: 30, done: true }

Why is the first call to it.next() skip arguments (in the code above, "bar") altogether? Or, in other words, why is the behavior different in subsequent calls? I would've expected calling the generator function would skip arguments, and that the call to next() would actually initialize the iterator, making the process more coherent, no?

user157251
  • 64,489
  • 38
  • 208
  • 350
Yanick Rochon
  • 45,203
  • 21
  • 112
  • 182
  • **I would've expected calling the generator function would skip arguments** If so you wouldn't be able to pass several arguments. `next` seems to only take into account the first argument it's passed. For this reason, the arguments for the iterator will be those passed to the generator. As a result, there is no way to get the optional argument of the first `next`. Those are all guesses though. – Loamhoof Jan 08 '14 at 10:17
  • You got a point there. However, if [destructuring assignments](https://developer.mozilla.org/en-US/docs/Web/JavaScript/New_in_JavaScript/1.7?redirectlocale=en-US&redirectslug=JavaScript%2FNew_in_JavaScript%2F1.7#Destructuring_assignment) are ever officialized, this could solve that. Ex: `var [a, b] = yield c;` would receive the arguments from `it.next(1, 2);`. – Yanick Rochon Jan 08 '14 at 14:20
  • 1
    This actually doesn't change anything, you wouldn't need destructuration. Destructuration would only work if yield "returns" an array. In this case, you could also save that array in one variable. Also, my point was that to be able to have the arguments of the first `next` be taken into account, you'd need some place to get them (no previous `yield` to "return" them), or they should be cast into the generator's arguments. The fact is, it would be illogical because `next` handles only 1 argument atm. But really, it could change. – Loamhoof Jan 08 '14 at 14:59
  • That could be an answer and I would upvote it. – Yanick Rochon Jan 08 '14 at 15:06
  • your example is obscenely complex, and you don't actually say whether or not you're using ECMAScript-harmony or JS 1.8. Title and tags don't match. – user157251 Jan 22 '14 at 17:35
  • @EvanCarroll, the tags says "ecmascript-harmony", and I have seen many examples that were "simple", but could not help me understand how generators worked; most of them using [Q](https://github.com/kriskowal/q) and not a pure JS example. – Yanick Rochon Jan 22 '14 at 17:39
  • @YanickRochon I asked a [duplicate question with a substantially simpler example, see if it makes more sense to you](http://stackoverflow.com/questions/21271216/in-es6-what-happens-to-the-arguments-in-the-first-call-to-an-iterators-next?noredirect=1#comment32066572_21271216). – user157251 Jan 22 '14 at 17:51
  • ECMAScript-Harmony isn't Javascript. Javascript has its own spec'd, and implimented versions of generators which don't require `function *` even. Javascript is a superset of ECMAScript and when ECMAScript is playing catch up the differentiation is required. – user157251 Jan 22 '14 at 17:57
  • @EvanCarroll, I'm sorry, I don't see the point of that comment. No offense, seriously, but my example and tag are clearly indicating ECMAScript harmony *and* my example is using the ECMAScript definition of the generator function. Why even making references to the JS 1.8 specs at all? As for your question, it is the same as mine :) But I think I'd rather like the answer here as it contains more details on the subject. My example was, perhaps, overly complicated, but demonstrated clearly the problem regardless. – Yanick Rochon Jan 22 '14 at 18:36
  • As for the edit. The precision might have not been necessary. The question applies to both JS and ECMA specs. – Yanick Rochon Jan 22 '14 at 18:37

1 Answers1

4

In the draft:

After some more research, the answer lies within harmony's draft (see the wiki: http://wiki.ecmascript.org/doku.php?id=harmony:generators#methodnext).

next is supposed to have no argument. However, it seems calling next with one argument is just equivalent to call send with one argument. Here lies the answer. send is designed to throw an error if called first (no next prior).

So basically, you should not be able to "initialize" your iterator by passing an argument to next cause you're not authorized to do so.

In the implementations:

However, this is just the specification. To summarize what's been said as comments, there are at least 2 reasons why you can't pass an argument to your first next and have to pass it to your generator.

The first one would be the fact that you would need some method to actually get this argument. You cannot do it the same way you'd do it with your next calls let myVar = yield myValue.
The second one would be that next only accepts one argument and that is quite limiting, whereas you can pass an infinite amount of arguments to your generator when producing the iterator.

However, this is only what's happening at the moment. Nothing says that the draft or implementations won't change. We could certainly imagine send accepting any number of arguments (no reason but hey, who knows), and being able to cast it into the generator's arguments. Or whatever.

Loamhoof
  • 8,163
  • 24
  • 29
  • `it seems calling next with one argument is just equivalent to call send with one argument` -- Is there any reference for this statement? I did not found it in the draft. Thank you! – zhiyelee Jul 22 '14 at 05:47
  • I got it. `send` method has been eliminated and replaced by an argument to the `next` method https://bugs.ecmascript.org/show_bug.cgi?id=1555 – zhiyelee Jul 22 '14 at 06:01
  • @zhiyelee it's been a while and things have evolved since then, but I guess this statement of mine was based on the implementations of generators at that time (chrome, ff), and maybe on something that was written on one of mozilla's page, can't tell you much more (and I guess it doesn't matter much anymore :)). – Loamhoof Jul 22 '14 at 09:14
  • Thank your for the response. – zhiyelee Jul 23 '14 at 01:57