-
Notifications
You must be signed in to change notification settings - Fork 13k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Iterator::nth
doesn't compose well
#60395
Comments
I'm not sure if we can get away with it (depending on the guarantees |
That more |
@Mark-Simulacrum That's a great point, an |
Would This is an extension of the general off-by-one confusion of |
@cuviper It would return
|
@Mark-Simulacrum Note that a chain of more than two iterators wouldn't be able to benefit from that specialization because |
Add Iterator::advance_by and DoubleEndedIterator::advance_back_by This PR adds the iterator method ```rust fn advance_by(&mut self, n: usize) -> Result<(), usize> ``` that advances the iterator by `n` elements, returning `Ok(())` if this succeeds or `Err(len)` if the length of the iterator was less than `n`. Currently `Iterator::nth` is the method to override for efficiently advancing an iterator by multiple elements at once. `advance_by` is superior for this purpose because - it's simpler to implement: instead of advancing the iterator and producing the next element you only need to advance the iterator - it composes better: iterators like `Chain` and `FlatMap` can implement `advance_by` in terms of `advance_by` on their inner iterators, but they cannot implement `nth` in terms of `nth` on their inner iterators (see rust-lang#60395) - the default implementation of `nth` can trivially be implemented in terms of `advance_by` and `next`, which this PR also does This PR also adds `DoubleEndedIterator::advance_back_by` for all the same reasons. I'll make a tracking issue if it's decided this is worth merging. Also let me know if anything can be improved, this went through several iterations so there might very well still be room for improvement (especially in the doc comments). I've written overrides of these methods for most iterators that already override `nth`/`nth_back`, but those still need tests so I'll add them in a later PR. cc @cuviper @scottmcm @Amanieu
This is no longer relevant now that |
Iterators like
iter::{Flatten, FlatMap, Chain}
that chain multiple iterators together aren't able to implementIterator::nth
in terms of thenth
method on their inner iterators, because whennth
returnsNone
, there's no way to know how many elements are "left".This can lead to surprisingly bad performance when the inner iterator has an efficient
nth
implementation. For example,(0..100_000).chain(0..100_000).nth(50_000)
has O(n) performance, even though it never reaches the second iterator.I don't really know if this is worth fixing, but if it is, a way to fix it could be to add a method similar to
nth
toIterator
that returnsResult<Self::Item, usize>
. TheErr
case represents the "remaining"n
(there's probably a better way to phrase that).I don't have any interesting benchmarks, but I can confirm that implementing what I've temporarily called
try_nth
forops::Range
anditer::Chain
makes(0..100_000).chain(0..100_000).nth(50_000)
run in constant time. So returningResult<Self::Item, usize>
indeed composes better. But again, this may not be worth fixing. 🙂The text was updated successfully, but these errors were encountered: