Function.Iterator 0.1

I love generators, or at least I think I do. I first learned about generators from Python's PEP 255.

In my own words, generators constructs iterators. Python and Mozilla's JavaScript 1.7 have similar syntax for generators. Unless you're using Rhino, however, you're not going to see that sugar any time soon in a portable environment.

I've been trying different variations of a good (generalized) solution that fills this portability gap, because I want to use generators -- or rather iterators today.

Keep in mind this is yet one variation, and I'd love for someone to come up with an awesome_er_ solution.

Check out the Specs for usage and also follow the How to Use section in this file.



Details

Author
Olmo Maldonado
Current version
0.1
GitHub
ibolmo/Function.Iterator.js
Downloads
1483
Category
Utilities
Tags
Report
GitHub Issues

Releases


Dependencies

  • _self_/_current_: Core/Class

How to use

The premise is simple. You either add all the functions to the arguments of the constructor (Function.Iterator) or you dynamically add more functions to the iterator.

The first case is pretty basic, and not too exciting. Here's an example:

Simple Iteration

    var iter = new Function.Iterator(function(){
        return 'a';
    }, function(){
        return 'b';
    }, function(){
        return 'c';
    });

    iter.each(function(character){
        console.log(character);
    });

Not exciting, like I said. Things get fun, though, when you push more functions.

Push functions

    iter.push(function letterD(){
        return 'd';
    });

    // since we called each method, we're at the end of our list of functions
    // and iter.next() is the letterD function      
    console.log(iter.next()); // 'd'

    // every call to each method resets back to the beginning

    iter.each(function(character){
        console.log(character);
    });

Here's the fun part. What do you think would happen if I did the following?

?? Generator

    var counter = 0;
    var iter = new Function.Iterator(function next(){ // name your method instead of using argument.callee (deprecated in ES5)
        iter.push(next);
        counter++;
    });

    iter.next(); // counter = 1
    iter.next(); // counter = 2
    iter.next(); // counter = 3
    // ...
    // ...
    iter.next(); // counter = n

If you've answered it's an Endless, or non-stopping, or w00t generator than you'd be right.

CAREFUL If you're not careful, you will have an endless -- and non responsive situation.

Doh! Generator

    var iter = new Function.Iterator(function next(){
        iter.push(next);
    });

    var result;
    while (result = iter.next()) console.log(result);  // you'll never stop!

As always the onus falls on the developer to watch out for these cases. You are given power, thus it is your responsiblity.

How to Stop

Normal Array.forEach and even Object::forEach in MooTools have no way of stopping your loops until they're finished.

Function.Iterator, however, comes with a nice Function.Iterator.stop function. This function will throw an Exception which the each method automatically catches to stop the looping.

To be clear: if you're not using each and you call too many next your script will throw an exception that needs to be handled.

StopIteration Exception Example

    var iter = new Function.Iterator(function(){
        return 'first';
    });

    iter.next(); // 'first'
    iter.next(); // StopIteration Error!

Catch the Exception

    var iter = new Function.Iterator(function(){
        return 'first';
    });

    try {
        while (true) iter.next();
    } catch (StopIteration){
    }

    // script continues without disrupting the control flow

This gives stop its power. Use wisely:

Using Stop to Finish Iteration

    var counter = 0;
    var iter = new Function.Iterator(function next(){
        iter.push(next);
        counter += 5;
    });

    iter.each(function(){ // yes you can still use each
        if (counter > 20) iter.stop();
    });

    // or old school
    // option A
    counter = 0;
    try {
        while (counter < 20) iter.next();
    } catch (StopIteration){
    }

    //option B
    counter =- 0;
    try {
        while (true){
            iter.next();
            if (counter > 20) iter.stop();  // or break;
        }
    } catch (StopIteration){
    }

Build

Build via Packager, requires MooTools Core to be registered to Packager already (ty cpojer)

./packager register /path/to/Function.Iterator.js
./packager build Funciton.Iterator.js/* > Function.Iterator.js

Todo

  • More meaningful examples: fib, co-routines
  • More helpful sugars: skip, continue

Discuss

A note on comments here: These comments are moderated. No comments will show up until they are approved. Comments that are not productive (i.e. inflammatory, rude, etc) will not be approved.

Found a bug in this plugin? Please report it this repository's Github Issues.

blog comments powered by Disqus