Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why do we need both iterable and iterator concepts?

In ECMAScript6 an iterator is an object with a next() method that returns an object with two properties: {value, done}. E.g.:

function createIterator(ra) {
    let i = 0;
    return {
        next() {
            if (i < ra.length)
                return {value: ra[i++],
                        done: false};
            else
                return {value: undefined,
                        done: true};
        }
    };
}

Having created an iterator one finds it is not very useful in its own right as there's no built-in syntax to take advantage of an iterator. Instead, one has to do things like:

    const it = createIterator(['a', 'b', 'c']);
    while (true) {
        const o = it.next();
        if (o.done)
            break;
        else
            console.log(o.value);
    }

"Iterable" on the other hand is an object with a Symbol.iterator property that has to be a no-argument function that returns an iterator:

function createIterable(ra) {
    let it = createIterator(ra);
    return {
        [Symbol.iterator]() {return it;}
    };
}

... and when we create an iterable we are finally able to use the for of syntax:

for (let v of createIterable(['a', 'b', 'c']))
    console.log(v);

Looking at the above code the added value of the "iterable" object over the "iterator" is not easily perceived. So why does Javascript need these two separate concepts of iterable and iterator? BTW this is what Java does as well so there must be some language-independent reason why it is a good idea to have these two distinct concepts.

like image 318
Marcus Junius Brutus Avatar asked Oct 19 '22 11:10

Marcus Junius Brutus


1 Answers

Conceptually, the object that implements the "iterator" interface just encapsulates the current state of an iteration operation. Once that iterator has been consumed (it.done === true) it cannot be re-used.

The [Symbol.iterator]() function of an "iterable" object returns a new iterator each time it's invoked.

In that respect, be wary of the OP's function which is potentially flawed since the object created by his createIterable function only allows for a one-off call to its Symbol.iterator function. It would fail if the object returned was passed to more than one for .. of operation. Ideally it should read:

function createIterable(ra) {
    return {
        [Symbol.iterator]() {
             return createIterator(ra);
        }
    }
}
like image 98
Alnitak Avatar answered Oct 27 '22 09:10

Alnitak