Read my book

I wrote books about Webpack and React. Check them out!

Friday, March 23, 2012

Implementing Generators in JavaScript Using Closures

Around a month ago I was invited to speak two hours for a bunch of newbie web developers. I mainly spoke about Python and Django. I also took a brief look at JavaScript while at it.

During the development of the JavaScript mini-presentation I came up with a nice and simple way to implement generators. And by this I don't mean "yield" introduced in JavaScript 1.7. Sure, it's a nice keyword but it won't work in every browser. In this post I'm going to show how to use closures to achieve the same effect.


Generators - What Are They?


Generator by prettywar-stl (CC BY-NC-ND)
Before getting any further with the technical details I would like to spend a while discussing the conceptual side. So what is a generator and how does it work?

A generator is something that contains some state and is able to generate new values. It derives those new values based on its internal state.

In other words it's lazy. It won't calculate anything till you ask it to. What's the point of having a construct such as this available?

It makes it easier to separate concerns. You can think generators as sources. Suppose you are writing a RSS reader. You could have a generator to represent some actual feed. As you request new values from it, it fetches a new post from the feed (starting from the newest or so).

In essence it's just one way to think about architecture. A generator can encapsulate some logic for you. Instead of having "ifs" and whatnot convoluting your app, you might be able to get away with a generator depending on your situation. This separation of logic gives you some flexibility as well since you can throw another generator there as the requirements change (or the boss tells you to).

Basic Implementation


In order to make it easy to implement custom generators, I've implemented the following helpers:



Take some time to chew on that. As you can see closures come in handy for storing the state. "generator" is actually a factory you can use to construct your own generators. "cycle" and "pows" are examples of this. These in turn are factories that may be used to construct specific kind of generators.

Development Ideas


As you can see it's really easy to generate series. We could also use them to generate ranges (ie. range(1, 8, 2) could return sequence as follows: 1, 3, 5, 7 like in Python). I'm going to leave that as an exercise to the reader.

You could use a range to extract values out of other generators. Ie. something like "while(r.next() !== null) {...}" where r is you range would work. Just having while(r.next()) will work in case your range contains only positive, non-zero values. If that looks ugly to you, just implement forEach or something similar.

Note that there's no reason to be stuck with only "next" method. You could try to add "prev" that allows to go back. Given the callback has been defined as a pure function, this should not be much of an issue. You just have to be careful about the way you deal with state.

Conclusion


l hope this brief post gave you some idea how to think beyond the box in JavaScript. Sometimes it's possible to extend the language you use just by utilizing it the right way. JavaScript in particular seems to be one of those languages particularly suitable for this.

You can find an interactive demo of the concept here. There's also some kind of a solution for the "range" problem I proposed with limited syntax (no support for stride).