-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
libs: stabilize iter module #19176
libs: stabilize iter module #19176
Conversation
|
@@ -232,6 +245,7 @@ pub trait Iterator<A> { | |||
/// assert!(it.next().is_none()); | |||
/// ``` | |||
#[inline] | |||
#[stable] | |||
fn peekable(self) -> Peekable<A, Self> { |
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.
We've had concerns in the past about peekable iterators, perhaps this could be #[unstable]
for now?
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.
Sure thing. What were the concerns?
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.
The example I've seen before is along the lines of:
fn main() {
let vec = vec![1, 2, 3, 4, 5];
let mut iter = vec.into_iter().peekable(); // peekable makes no difference
let a: Vec<int> = iter.by_ref().take_while(is_odd).collect(); // takes 1, drops 2
let b: Vec<int> = iter.by_ref().take_while(is_even).collect(); // drops 3
let c: Vec<int> = iter.by_ref().take_while(is_odd).collect(); // drops 4
let rest: Vec<int> = iter.collect();
println!("a={} b={} c={} rest={}", a, b, c, rest);
} // prints a=[1], b=[], c=[], rest=[5]
fn is_odd(&x: &int) -> bool {
x % 2 == 1
}
fn is_even(&x: &int) -> bool {
x % 2 == 0
}
The problem here being that the methods like skip_while
and take_while
consume elements even though they in theory can preserve the elements of the underlying iterator if its peekable. Which is to say that SkipWhile<Peekable<T>>
can actually not consume an element when the SkipWhile
starts to return None
, but it has to perform like SkipWhile<T>
where it always consumes the element that returns None
.
This may be a problem with skip_while
or take_while
as well, just wanted to make sure that these concerns were here.
I know that I've personally found it somewhat clunky to use. I generally only have an Iterator<T>
instead of a Peekable<Iterator<T>>
and then having to pass a Peekable
all over the place is pretty painful. That's pretty fundamental though, and I'm not sure there's anything that we can do to alleviate my personal concern here.
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 sounds like an argument that skip_while
and take_while
should use peek
internally, so really a complaint about those adapters rather than peekable
itself. Is that right?
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.
Kind of I think, more that skip_while
and take_while
should only be defined on peekable iterators. The other suggestion was to make peek-ability a trait rather than an iterator.
@aturon just one design question about |
Thanks @alexcrichton! I'm going to look into the by-value convention. @thestinger, given that the splitting of traits here (necessitated by the new object safety rules) now makes all these adapters usable on trait objects in principle, is the only downside you see the additional |
05da0a3
to
741fa63
Compare
@alexcrichton I've pushed an update that switches to by-value where it makes sense. There was literally no fallout in all of the Rust distro (other than useless I've also tweaked the stability attributes of I'm leaving |
4fa0b4e
to
3d7e9aa
Compare
This is an initial pass at stabilizing the `iter` module. The module is fairly large, but is also pretty polished, so most of the stabilization leaves things as they are. Some changes: * Due to the new object safety rules, various traits needs to be split into object-safe traits and extension traits. This includes `Iterator` itself. While splitting up the traits adds some complexity, it will also increase flexbility: once we have automatic impls of `Trait` for trait objects over `Trait`, then things like the iterator adapters will all work with trait objects. * Iterator adapters that use up the entire iterator now take it by value, which makes the semantics more clear and helps catch bugs. Due to the splitting of Iterator, this does not affect trait objects. If the underlying iterator is still desired for some reason, `by_ref` can be used. (Note: this change had no fallout in the Rust distro except for the useless mut lint.) * In general, extension traits new and old are following an [in-progress convention](rust-lang/rfcs#445). As such, they are marked `unstable`. * As usual, anything involving closures is `unstable` pending unboxed closures. * A few of the more esoteric/underdeveloped iterator forms (like `RandomAccessIterator` and `MutableDoubleEndedIterator`, along with various unfolds) are left experimental for now. * The `order` submodule is left `experimental` because it will hopefully be replaced by generalized comparison traits. * "Leaf" iterators (like `Repeat` and `Counter`) are uniformly constructed by free fns at the module level. That's because the types are not otherwise of any significance (if we had `impl Trait`, you wouldn't want to define a type at all). Closes rust-lang#17701 Due to renamings and splitting of traits, this is a: [breaking-change]
@@ -694,7 +742,8 @@ pub trait RandomAccessIterator<A>: Iterator<A> { | |||
/// | |||
/// `Iterator::size_hint` *must* return the exact size of the iterator. | |||
/// Note that the size must fit in `uint`. | |||
pub trait ExactSize<A> : DoubleEndedIterator<A> { | |||
#[unstable = "could move DoubleEndedIterator bound onto rposition with method-level where clauses"] | |||
pub trait ExactSizeIterator<A> : DoubleEndedIterator<A> { |
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.
Can/should we decouple these? ExactSize makes sense for HashMap but DoubleEndedIterator doesn't really. Although granted ExactSize is only used for DoubledEndedIteration. CC #19327
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.
I concur. ExactSize has become something more than it was when introduced (used for backwards enumeration).
This is an initial pass at stabilizing the `iter` module. The module is fairly large, but is also pretty polished, so most of the stabilization leaves things as they are. Some changes: * Due to the new object safety rules, various traits needs to be split into object-safe traits and extension traits. This includes `Iterator` itself. While splitting up the traits adds some complexity, it will also increase flexbility: once we have automatic impls of `Trait` for trait objects over `Trait`, then things like the iterator adapters will all work with trait objects. * Iterator adapters that use up the entire iterator now take it by value, which makes the semantics more clear and helps catch bugs. Due to the splitting of Iterator, this does not affect trait objects. If the underlying iterator is still desired for some reason, `by_ref` can be used. (Note: this change had no fallout in the Rust distro except for the useless mut lint.) * In general, extension traits new and old are following an [in-progress convention](rust-lang/rfcs#445). As such, they are marked `unstable`. * As usual, anything involving closures is `unstable` pending unboxed closures. * A few of the more esoteric/underdeveloped iterator forms (like `RandomAccessIterator` and `MutableDoubleEndedIterator`, along with various unfolds) are left experimental for now. * The `order` submodule is left `experimental` because it will hopefully be replaced by generalized comparison traits. * "Leaf" iterators (like `Repeat` and `Counter`) are uniformly constructed by free fns at the module level. That's because the types are not otherwise of any significance (if we had `impl Trait`, you wouldn't want to define a type at all). Closes #17701 Due to renamings and splitting of traits, this is a: [breaking-change]
This is an initial pass at stabilizing the
iter
module. The module isfairly large, but is also pretty polished, so most of the stabilization
leaves things as they are.
Some changes:
into object-safe traits and extension traits. This includes
Iterator
itself. While splitting up the traits adds some complexity, it will
also increase flexbility: once we have automatic impls of
Trait
fortrait objects over
Trait
, then things like the iterator adapterswill all work with trait objects.
value, which makes the semantics more clear and helps catch bugs. Due
to the splitting of Iterator, this does not affect trait objects. If
the underlying iterator is still desired for some reason,
by_ref
canbe used. (Note: this change had no fallout in the Rust distro except
for the useless mut lint.)
convention. As such, they
are marked
unstable
.unstable
pending unboxedclosures.
RandomAccessIterator
andMutableDoubleEndedIterator
, along withvarious unfolds) are left experimental for now.
order
submodule is leftexperimental
because it will hopefullybe replaced by generalized comparison traits.
Repeat
andCounter
) are uniformlyconstructed by free fns at the module level. That's because the types
are not otherwise of any significance (if we had
impl Trait
, youwouldn't want to define a type at all).
Closes #17701
Due to renamings and splitting of traits, this is a:
[breaking-change]