Skip to content

Instantly share code, notes, and snippets.

@jorendorff
Forked from getify/gist:9105362
Last active August 29, 2015 13:56
Show Gist options
  • Save jorendorff/9192015 to your computer and use it in GitHub Desktop.
Save jorendorff/9192015 to your computer and use it in GitHub Desktop.
function* range(start, stop, step=1) {
for (var i = start; i < stop; i += step)
yield i;
}
for (var n of range(0, 100, 3))
console.log(n);
@getify
Copy link

getify commented Feb 25, 2014

My real use-case is still an in-flux experiment and harder to illustrate without a bigger problem domain. At the moment, it involves a "runner" that negotiates between two simultaneous generators, where it receives and sends back in promises to each, respectively, based on their activity (kinda like cooperative threading). My runner has to iterate these generators manually, as I showed. At the moment it works, but it's rough.

One of the things I was exploring to make it less rough was having for-of loops (which are of course themself yieldable if the runner itself is a generator) running each main generator. But that would require me to be able to send in promises via the loop's hidden .next(..) call to be terribly useful.

I am not positive that this approach I'm experimenting with will actually lead to real code I use. I'm optimistic that I might be on to a few things, but as I start to apply the pattern to some of my real code, I may realize it falls apart.

I was, rather, hoping with this exploration that it could be a general instead of specific example of the idea that sometimes iterations over a generator benefit from being able to send values into the generator at each step.

For example, generators that are manually advanced like:

function* scoreboard(v) {
   while (v < 100) {
      v += yield v;
   }
   return v;
}

var g = scoreboard(0);

g.next(); // { done:false, value: 0 }

g.next(10);  // { done:false, value: 10 }
g.next(25);  // { done:false, value: 35 }
g.next(50);  // { done:false, value: 85 }
g.next(100); // { done:true, value: 185 }

That same sort of task (again, I know a trivial example) can be iterated (manually) with values sent in at each iteration:

var my_scores = [10,25,50,100], x, y, ret, it;

// play my game
for (it = scoreboard(0);
   !(ret && ret.done) && (ret = it.next(y)) && ((x = ret.value) || 1);
) {
   console.log("score: " + x);
   y = my_scores.shift(); // get my next score
}

console.log("Game over: " + x); // Game over: 185

So this manual iteration "works", but it sucks compared to having native syntactic support for the for-of loop to do the same thing:

var my_scores = [10,25,50,100], x, y;

// play my game
for (x of scoreboard(0):y) {
   console.log("score: " + x);
   y = my_scores.shift(); // get my next score
}

console.log("Game over: " + x); // Game over: 185

The key thing is that the outside scope, the scope with the for..of loop in it, has extra information to send in to each "iteration" of the generator. next(..) does that job well when you manually iterate. I wish there was a way when you for..of iterate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment