-
Notifications
You must be signed in to change notification settings - Fork 1.6k
RFC: Split Iterator into Iterator and FiniteIterator #74
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
Conversation
A subtlety here is you can have iterators that can be infinite but are often used in a non-infinite fashion, e.g. repeat(10).take_while(|x| x < 100); // infinite
count(0, 1).take_while(|x| x < 100); // finite Obviously those two examples are silly, but they do indicate that |
(I guess that adds to your Also, BTW, |
|
||
# Alternatives | ||
|
||
Not doing this would mean that it's possible to write generic code that uses Iterator trait bound |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is still possible with these changes. An example would be maybe_infinite.take_while(|x| x < 100)
. The TakeWhile
iterator is not always infinite, but sometimes it is. It can prevent some of these cases but not all. Since iterators and iterator adaptors can have effects, infinite loops may be intentional.
Thanks for feedback! I have changed my proposal to include only these functions from Iterator trait that always result in an infinite loop. I hope it is better now. |
This doesn't seem very useful to me. Misuse of an infinite iterator should be easy to detect because a program will crash or just hang. And as @huonw said, it's not always clear what some functions should return. |
I think that functions which may return a finite iterator should do it anyway. Is creating an Alternative name for One way to resolve this is to make it clear that the |
I will try to flesh out the details of a possible solution as if they were documented, also per @huonw's request. Trait core::iter::ItemStream
pub trait ItemStream<A> {
fn next(&mut self) -> Option<A>;
fn chain<U: ItemStream<A>>(self, other: U) -> Chain<Self, U> { ... }
fn zip<B, U: ItemStream<B>>(self, other: U) -> Zip<Self, U> { ... }
fn map<'r, B>(self, f: |A|: 'r -> B) -> Map<'r, A, B, Self> { ... }
fn filter<'r>(self, predicate: |&A|: 'r -> bool) -> Filter<'r, A, Self> { ... }
fn filter_map<'r, B>(self, f: |A|: 'r -> Option<B>) -> FilterMap<'r, A, B, Self> { ... }
fn enumerate(self) -> Enumerate<Self> { ... }
fn peekable(self) -> Peekable<A, Self> { ... }
fn skip_while<'r>(self, predicate: |&A|: 'r -> bool) -> SkipWhile<'r, A, Self> { ... }
fn take_while<'r>(self, predicate: |&A|: 'r -> bool) -> TakeWhile<'r, A, Self> { ... }
fn skip(self, n: uint) -> Skip<Self> { ... }
fn take(self, n: uint) -> Take<Self> { ... }
fn scan<'r, St, B>(self, initial_state: St, f: |&mut St, A|: 'r -> Option<B>) -> Scan<'r, A, B, Self, St> { ... }
fn flat_map<'r, B, U: ItemStream<B>>(self, f: |A|: 'r -> U) -> FlatMap<'r, A, Self, U> { ... }
fn fuse(self) -> Fuse<Self> { ... }
fn inspect<'r>(self, f: |&A|: 'r) -> Inspect<'r, A, Self> { ... }
fn by_ref<'r>(&'r mut self) -> ByRef<'r, Self> { ... }
fn advance(&mut self, f: |A| -> bool) -> bool { ... }
fn collect<B: FromItemStream<A>>(&mut self) -> B { ... }
fn nth(&mut self, n: uint) -> Option<A> { ... }
fn all(&mut self, f: |A| -> bool) -> bool { ... }
fn any(&mut self, f: |A| -> bool) -> bool { ... }
fn find(&mut self, predicate: |&A| -> bool) -> Option<A> { ... }
fn position(&mut self, predicate: |A| -> bool) -> Option<uint> { ... }
}
An item stream yields a (potentially-empty, potentially-infinite) sequence of values.
(Alternatively renamed to a different meaningful name.)
Implementors
Repeat<A>
Counter<A>
Chain<T, U>
Zip<T, U>
Cycle<T>
etc... Trait core::iter::Iterator
trait<A> Iterator<A> : ItemStream<A> {
fn size_hint(&self) -> (uint, Option<uint>) { ... } // doesn't it belong here?
fn last(&mut self) -> Option<A> { ... }
fn fold<B>(&mut self, init: B, f: |B, A| -> B) -> B { ... }
fn len(&mut self) -> uint { ... }
fn count(&mut self, predicate: |A| -> bool) -> uint { ... }
fn max_by<B: TotalOrd>(&mut self, f: |&A| -> B) -> Option<A> { ... }
fn min_by<B: TotalOrd>(&mut self, f: |&A| -> B) -> Option<A> { ... }
}
An interface for iterating over a collection or other (potentially-empty) finite sequence of values.
Implementors
Chain<T: Iterator<A>, U: Iterator<A>>
Zip<T: Iterator<A>, U: ItemStream<A>>
Zip<T: ItemStream<A>, U: Iterator<A>>
etc... Yet another trait is possible, even though it has very little value: trait<A> UnboundedStream<A> : ItemStream<A> {
fn next_value(&mut self) -> A;
} Traits AdditiveIterator, MultiplicativeIterator, OrdIterator are not implemented for T: ItemStream |
I have realized that Zip<T, U> is also problematic. It's finite if either T or U are finite. It would need to be something like:
|
@Sawyer47 This alternation can be notated as two similar implementations. I'll add these to my comment. Dzięki. |
@pczarn Are you sure? This code doesn't compile:
Compilation errors:
|
@Sawyer47 Oh, multiple implementations of a trait in the current trait system are forbidden, because distinct parameters ( |
Thanks for the RFC! The core team has decided, however, to not accept this for now. We believe that the increase in complexity isn't worth what' we're gaining from this RFC. Closing. |
added test for filter_map function of streams
Describes my proposal to split existing Iterator trait into Iterator and FiniteIterator traits. Some functions from Iterator shouldn't be invoked on infinite iterators.
It's my first attempt to contribute to Rust. I hope this RFC makes sense.