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
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • 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 24, 2014

This misses my main motivation, which @allenwb picked up one with his closure-trick in the previous gist's comments:

I have several cases in my current code/experiments where I want to use contextual information in the scope of the iteration (that is, the for-of loop) to control how the iterator behaves. It's not just a "at the time of starting, set a step". My use case involves passing in special values during the iteration, such as promises created for instance, that affect how the iteration proceeds.

If you look at the last (fifth) snippet, I show how I can do that manually without a for-of loop, by calling next(..) manually, but that's uglier than if there was a syntax in the loop to pass along something to the syntactically hidden next(..) call.

I'm sorry you think that's a "mistake", but it's my valid use case, and I'd just wish I had optional syntax for it instead of having to abandon for-of loops when I need to have more control over the iteration.

@jorendorff
Copy link
Author

Right, this particular snippet was only meant to answer your specific question in https://twitter.com/getify/status/436334051566571520 . That is, I was just trying to illustrate what Brendan meant in his tweet that you were replying to.

I read all your snippets.

My use case involves passing in special values during the iteration, such as promises created for instance, that affect how the iteration proceeds.

Can you be any more specific? I think your real use case is bound to be more interesting than the ones in your gist.

@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