I was first introduced to the concept of “generators” in Python, and quite frankly, I couldn’t immediately see the added value of generators because I couldn’t think of use cases off the top of my head.
Recently, I stumbled upon a use case that fit “generators” almost perfectly and it doesn’t involve “generating” anything, so In this article I will try to briefly explain what generators are and how they work and demonstrate a use case for generators that doesn’t involve “generating”.
What are these “generators” anyway?
Generators is a new feature in ECMAScript 6. A generator is a “kind of” a function that contains the keyword “yield”, so the central piece in understanding what generators are and how they work is understanding the keyword “yield”.
The best way to think about “yield” is that it simply pauses the execution of a function, consider the following code
So what “yield” does here is basically halting execution and “yielding” control to the calling code. Any subsequent call to the next() method would pick up where it left and continue until it faces another “yield” or a “return”.
This feature is very powerful and is usually used with loops, for example
Upon the first call to the next() method, the loop starts with i=0 and then it encounters a “yield” so it yields the value of 0 to the calling code and pauses the execution, calling the next() method a second time would pick up at line 5 and output ‘resuming’ to the console, increment i by one, output ‘pausing’ to console and yield a value of 1 and so on.
Do “generators” have other uses?
So this neat new feature is called “generators”, but don’t let the name fool you, the “yield” keyword and “generators” can be used for more than just “generating a sequence of values”, remember that at the most basic level the “yield” keyword is just about pausing and resuming the execution of a function.
The use case that I want to share with you today is the ability to let the user control any iterative process, that is, allowing the user to pause and resume the execution of loop at arbitrary points. Think of this as giving the power of the breakpoints to the end-user and wrapping that in some HTML5 goodness, this can be particularly handy in instructional or educational contexts.
In my use case I was trying to build a step-by-step artificial neural network visualization. I wanted the user to be able to take controlled steps in the iterative process of training. An artificial neural network training loop is highly nested and it looks something like this.
I wanted to let the user pause the execution after each iteration of the “i” loop or maybe after each iteration of the “j” loop or the “k” loop. I want to allow the user to gain insight on how the calculations are performed in each cycle and develop an intuition as to how the process of training converges to an answer. Trying to implement that without the “yield” keyword is a NIGHTMARE, so let’s not do that.
Implementing this functionality using “yield” is fairly straight forward and clean. We can modify the code above to allow user control by yielding.
As long as breakMode == “i”, the code will reach line 24 and then yield, subsequent calls to this generator will pickup where it left, complete one iteration of the “i” loop and then yield again. if the user changes the breakMode to “j” and then call the generator again, the execution would pick up from the following line (line 25) and continue until line 20 where it will yield.
The code above can be modified to allow a specific number of iterations before yielding, say for example we want to run 10 iterations of the “i” loop and then pausing or maybe 4 iteration of “k” loop and then pausing.
I am generally a simple-minded guy who likes step-by-step visualization to grasp a concept. I think with the power of HTML5 and generators such step-by-step visualizations are much easier to implement.