6

On Mozilla's page iterators and generators there is a statement:

While custom iterators are a useful tool, their creation requires careful programming due to the need to explicitly maintain their internal state. Generators provide a powerful alternative: they allow you to define an iterative algorithm by writing a single function which can maintain its own state.

Regarding above explanation, isn't it possible to write an iterative algorithm without Generators, such as:

Array[Symbol.iterator] = function(){
    return {
        next: function(){
            //logic
            return {
                value: "",
                done:false
            }
        }
    }
}

Can't get my head around. Could someone explain what is the main reason they created an alternative, seems not much different to me.

serkan
  • 6,885
  • 4
  • 41
  • 49

2 Answers2

13

They might look pretty similar on the surface, but they can be used in very different ways.

Iterators and Iterables

Iterators are rather strictly defined: they are object (the iterators) which contains a next (and possibly a few other) function. Every time the next function is called, it is expected to return an object with two properties:

  • value: the current value of the iterator
  • done: is the iterator finished?

An iterable on the other hand is an object which has a property with a Symbol.iterator key (which represents the well know symbol @@iterator). That key contains a function, which when called, returns a new iterator. An example of an iterable:

const list = {
    entries: { 0: 'a', 1: 'b' },
    [Symbol.iterator]: function(){
        let counter = 0;
        const entries = this.entries;
        return {
            next: function(){
                return {
                    value: entries[counter],
                    done: !entries.hasOwnProperty(counter++)
                }
            }
        }
    }
};

Their main purpose, as their name suggests, is to provide an interface which can be iterated:

for (let item of list) { console.log(item); }
// 'a'
// 'b'

Generators

Generators on the other hand are much more versatile. It helps to think of them as functions which can be paused and resumed.

While they can be iterated (their iterables provide a next method), they can implement much more sophisticated procedures and provide a input/output communication through their next method.

A simple generator:

function *mygen () {
   var myVal = yield 12;
   return myVal * 2;
}

const myIt = mygen();

const firstGenValue = myIt.next().value;
// Generator is paused and yields the first value

const result = myIt.next(firstGenValue * 2).value;

console.log(result); // 48

Generator delegation

Generators can delegate to another generator:

function *mydelgen(val) {
    yield val * 2;
}

function *mygen () {
    var myVal = yield 12;
    yield* mydelgen(myVal); // delegate to another generator
}

const myIt = mygen();
const val = myIt.next().value;
console.log(val);
console.log(myIt.next(val).value);
console.log(myIt.next().value);

Generators & Promises

Generators and Promises together can create a sort of automatic asynchronous iterator with the help of utilities such as co.

co(function *(){
  // resolve multiple promises in parallel
  var a = Promise.resolve(1);
  var b = Promise.resolve(2);
  var c = Promise.resolve(3);
  var res = yield [a, b, c];
  console.log(res);
  // => [1, 2, 3]
}).catch(onerror);

In Conclusion

So in conclusion one could say that the main purpose of iterators is to create an interface for custom objects to be iterated, whereas generators provide a plethora of possibilities for synchronous and asynchronous workflows:

  • stateful functions
  • generator delegation
  • generators & promises
  • CSP

etc.

nils
  • 25,734
  • 5
  • 70
  • 79
  • *"Iterators are rather strictly defined. They return an object which contains a next (and possibly some other) function."* That doesn't right. Iterators are objects, they don't return anything. They have a `next` function *themselves*. Or do you mean *iterables*, rather than iterators? *"An example of an iterator:"* `list` is an iterable in your example. See also http://www.ecma-international.org/ecma-262/6.0/index.html#sec-iteration . – Felix Kling May 09 '16 at 21:55
  • @FelixKling thanks, those terms have confused me a bit. Is there a name for the function which is assigned to `Symbol.iterator` in an iterable? – nils May 10 '16 at 06:28
  • @FelixKling Just out of curiosity, how did you learn to navigate the spec? I know a few sections, but still have trouble reading other sections (especially syntax sections such as http://www.ecma-international.org/ecma-262/6.0/index.html#sec-object-initializer). Is there a guide that explains the most important terms somewhere? – nils May 10 '16 at 06:32
  • Some are things explained here: http://www.ecma-international.org/ecma-262/6.0/index.html#sec-syntactic-grammar . Reading about grammars in general, especially about Backus-Naur-Form would be helpful as well. As for the specifics of the spec, it's a lot of reading (on and off) (as needed) and gradually moving towards more complex topics... There are still notations I can't easily interpret, even though I understand them in theory. It certainly took me a while to understand the spec as I do now. Starting small and not trying to understand everything at once worked for me. – Felix Kling May 10 '16 at 06:41
2

Isn't it possible to write an iterative algorithm without Generators.

No, it's not. Yes, it is possible to write every generator algorithm as a custom iterator, but the // logic in your code will be much more complicated. The emphasis of the statement is that it won't be iterative any more, it will be recursive.

As an exercise, here's a quite simple iterative generator function:

function* traverseTree(node) {
    if (node == null) return;
    yield* traverseTree(node.left);
    yield node.value;
    yield* traverseTree(node.right);
}

Try to rewrite it as a custom iterator. Whether you get stuck or get it done, it will show you what the difference is.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • [Here's a possible solution](http://stackoverflow.com/a/23614292/1048572) I once scribbled, but I'm not even sure whether it's correct. – Bergi May 09 '16 at 20:56