Generators

Generators are really powerful in BooJs, they differ from standard Boo (or C#) and model instead the pattern found in Python or Mozilla’s JavaScript.

In summary, every generator becomes a coroutine not only able to halt execution at arbitrary points in order to return a value but also to receive values and exceptions from the outer context. These features make generators a great primitive for co-operative multitasking and event driven programming in general, for instance the Async library is built on top of generators.

JavaScript engines, with the exception of Mozilla’s and recent V8 builds, do not offer native support for this kind of generator. The BooJs compiler will instrument the code, converting the generator to a state machine able to handle halting and resuming execution at arbitrary points. While the generated code is convoluted it shows to be pretty fast on modern browsers, it runs roughly at half the speed of an user land forEach implementation and about 70% the speed of Mozilla’s native generators.

Generator interface

BooJs exposes Mozilla’s iterator and generator interfaces since they are being standardized in ES6 (aka JavaScript Harmony) there is a chance that in the future they get adapted to closely follow the standard. Basically a generator returns a GeneratorIterator which implements Iterator for next() and also offers send(value), throw(error) and close().

Native support

The compiler only targets standard JavaScript 1.5, not generating alternative code paths for specific browsers. This is something that will probably change in the future but currently generators always get instrumented and thus are not as performant as native implementations, although they aren’t as slow as they might seem!

Even if native support is not used, BooJs generators offer a compatible API and hence should work properly on every environment, including their use with native generator loop constructs.

Closing generators

Generators keep state and allow to use ensure (aka finally) blocks inside them so there is a need to properly close and dispose them. Boo for loop construct understands the GeneratorIterator interface and is able to close them when the iteration is over. However when manually iterating them you are responsible for properly closing the generators.

# Infinite generator
def gen():
    i = 1
    try:
        while true:
            yield i++
    ensure:
        print 'exited'

# Automatically closed by the compiler
for _, i in zip(range(3), gen()):
    print i
# Outputs: 1, 2, 3, 'exited'

# Manually closing the generator
g = gen()
for i in range(3):
    print g.next()
# Outputs: 1, 2, 3
g.close()
# Outputs: exited