Saturday, November 14, 2009

Generator functions in Go

When I learned how channels work in Google's Go language, one of the first thoughts that came to my mind was not inter-thread communication, but generator functions ala Python's yield statement.  That is because of the Wikipedia article on the subject, which mentions that Java can implement generators via threading.  Common threading, however, is not always a quick and easy process, so I more-of-less decided that the feature could only really work well in languages that explicitly have the feature.  That is not the case with Go.

Goroutines are a light-weight implementation of threading, without much of the complexity associated with threading.  All you need to launch a goroutine is any function and the 'go' keyword.  Channels can help for passing data out of goroutines and when channels are created without defining a buffer size, they block execution until the channel is read from.  That feature of channels is very similar to what Python's 'yield' statement does.

func Count (start, length int) chan int {
    yield := make (chan int);

    go func () {
        for num := start; num < start + length; num++ {
            yield <- num

        close (yield)
    } ();

    return yield

As you can see, it's slightly different from Python, but very workable and without much difficulty.  The actual code for the generator is held within an anonymous function, but outside of that all we do is create the channel and return it.

Note that the channel is closed at the end of the generator.  This is important, as trying to read beyond the end of the goroutine causes the program to panic and die.  If, on the other hand, the channel is closed and one reads beyond the end of the goroutine, the result is simply zeros.

Another great feature of channels is that they are one of the types that may be used by the 'range' clause in 'for' loops.  Thus, in such a loop one does not have to check to see if the channel is closed; Go does that for you.

No comments:

Post a Comment