Bidirectional iterators

We currently have unidirectional iterators, which are very useful in many areas. However, these come with major caveats:

  • If you need to have a navigable view of an iterable list, you have to buffer all entries of that list.
  • When displaying large files, it's generally far more efficient to read only parts of it at a time.
  • It's not uncommon to want to "reverse" an iterator, hence why so many languages provide it. Normally, in languages like Python that lack this feature, this involves loading the whole iterator into a buffer and then reading the buffer backwards, but this is highly inefficient in terms of memory for most collections.
  • This would provide a natural "undo" functionality, and a future syntax addition could provide this for generators that support it.
  • What prompted me to suggest this now is I'm currently designing an infinite scroller component, and it's way simpler and easier to accept a reversible iterator than to try to control the world by fetching and managing an internal list of everything.

So my proposal: add an optional iter.previous(value?) to the iterator protocol, as a mirror of iter.next(value?) with the same return value and everything.

  • Where next advances the state forward, previous advances the state back.
  • Where next on first call initializes the iterator at the start, previous initializes the iterator at the end.

This would also be added to various built-in iterators where applicable, like array, map, and set iterators. And of course with the iterator helpers proposal, an iter.reversed() utility could be created that works more or less like this:

function addReversed(Iterator) {
    class ReverseIterator extends Iterator {
        constructor(iter) { this._iter = iter }
        next(value) { return this._iter.previous(value) }
        previous(value) { return this._iter.next(value) }
    }

    Iterator.prototype.reversed = function () {
        return new ReverseIterator(
            this.prev == null ? [...this].values() : this
        )
    }
}

addReversed(Iterator)
addReversed(AsyncIterator)

As for language precedent:

see https://github.com/tc39/proposal-reverseIterator

1 Like