On Wed, Feb 3, 2021 at 5:09 PM Levi Morrison <le...@php.net> wrote: > On Wed, Feb 3, 2021 at 8:50 AM Nikita Popov <nikita....@gmail.com> wrote: > > > > On Wed, Feb 3, 2021 at 4:38 PM Levi Morrison <le...@php.net> wrote: > >> > >> Hello, everyone! > >> > >> This proposal adds two new classes to the SPL: > >> > >> - `Spl\ReverseArrayIterator`. It iterates over an array in reverse > >> order. It does not duplicate the array. > >> - `Spl\ForwardArrayIterator`. It iterates over an array in forward > >> (normal) order. It does not duplicate the array. > >> > >> They both implement Countable which returns the `count()` of the > >> array. The [PR][1] has some examples and discusses why I am proposing > >> `ForwardArrayIterator` when there is already `ArrayIterator`, the > >> short of which is for performance. There are timing numbers in [one of > >> the comments][2]. > >> > >> When it comes time to vote I may merge this into another RFC with > >> [`CachedIterable` by Tyson Andre][3], which I recommend readers also > >> take a look at. Whether we team up for the RFC vote or not, I wanted > >> to get this out there for discussion and review. > >> > >> [1]: https://github.com/php/php-src/pull/6535 > >> [2]: https://github.com/php/php-src/pull/6535#issuecomment-769179450 > >> [3]: https://github.com/php/php-src/pull/6655 > > > > > > Hey Levi, > > > > I like the general idea of having an "ArrayIterator but sane". > > > > That said, I don't think that the ReverseArrayIterator + > ForwardArrayIterator pair of iterators approaches this problem correctly. > There are plenty of iterators that could be run in reverse, and I think it > would be silly to create two classes for each of them. E.g. if we introduce > an ObjectPropertyIterator, should there be both > ForwardObjectPropertyIterator and ReverseObjectPropertyIterator? I don't > think so. > > > > I think the correct abstraction for bidirectional iterators is to > introduce an interface > > > > // Or "ReversibleIterator" > > interface BidrectionalIterator extends Iterator { > > public function prev(): void; > > public function end(): void; > > } > > > > and then a class along the lines of: > > > > class ReverseIterator implements BidirectionalIterator { > > public function __construct(private BidirectionalIterator $iter) {} > > > > public function next() { $this->iter->prev(); } > > // etc. > > } > > > > This would replace "new ReverseArrayIterator($array)" with "new > ReverseIterator(new ArrayIterator($array))", but in a way that is general, > and composes. > > > > Regards, > > Nikita > > I wrote an implementation of this idea two years ago: > > https://github.com/php/php-src/compare/master...morrisonlevi:BidirectionalArrayIterator > > It's fine for arrays, but not all structures that you can iterate > through forward or reverse. For instance, tree structures can be > traversed forward or reverse, but bidirectionally is far more > difficult (and I did not find any pre-existing solutions in this > space, btw). I do have repositories with tree structures, so it's not > just theoretical. >
I don't really view this as a problem, in the sense that you always have the option of implementing two iterators. But for most cases, if you can iterate in reverse, you can also iterate bi-directionally. > Another factor for abandonment was ergonomics. This is not great: `new > ReverseIterator(new BidirectionalArrayIterator($array))`. It's mildly > less performant as well, having to create two objects, and then having > delegation through methods. > It is slightly less ergonomic in isolation, but I think it makes more sense conceptually. Iterating an array in reverse is not exactly common (to the point that I'm not even sure this is a problem worth solving), so I don't think it needs to be optimized for minimum characters. Regards, Nikita