From a70eefaa3f5d7ec007c0fdb43abbdfa09a0714a4 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Thu, 20 Mar 2014 21:18:42 -0700 Subject: [PATCH 1/4] RFC for adding an `IntoIterator` trait --- 0000-into_iterator.md | 83 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 0000-into_iterator.md diff --git a/0000-into_iterator.md b/0000-into_iterator.md new file mode 100644 index 00000000000..c90ab94c3bb --- /dev/null +++ b/0000-into_iterator.md @@ -0,0 +1,83 @@ +- Start Date: 2014-03-20 +- RFC PR #: (leave this empty) +- Rust Issue #: (leave this empty) + +# Summary + +Add an `IntoIterator` trait that allows a function to consume both an iterator +and a value that can be converted into an iterator. + +# Motivation + +We have some unnecessary redundancy in some of our collection APIs: + + * `Vec::push_all` is designed to take one `Vec` and merge it into another. + * `Extendable::extend` takes an Iterator and merges it into a value. + * `vec::append` copies and merges one `Vec` with anther `Vec`. + +# Detailed design + +This redundancy can be eliminated with a simple trait: + +``` +trait IntoIterator> { + fn into_iterator(self) -> Iter; +} +``` + +Here is how it would be used with `Vec`: + +``` +use std::vec_ng::{Vec, MoveItems}; + +impl IntoIterator> for MoveItems { + fn into_iterator(self) -> MoveItems { self } +} + +impl IntoIterator> for Vec { + fn into_iterator(self) -> MoveItems { self.move_iter() } +} +``` + +Almost every value and Iterator will have the same implementation so this could +be a good use case for a macro. + +Here is a demonstration on how they would be used: + +``` +trait MyExtendable { + fn my_extend, IntoIter: IntoIterator>(&mut self, x: IntoIter); +} + +impl MyExtendable for Vec { + fn my_extend, IntoIter: IntoIterator>(&mut self, x: IntoIter) { + let mut iter = x.into_iterator(); + let (size, _) = iter.size_hint(); + self.reserve_additional(size); + + for x in iter { + self.push(x); + } + } +} + +fn main() { + let mut a = Vec::new(); + a.my_extend(vec!(4, 5, 6)); + a.my_extend(vec!(7, 8, 9).move_iter()); + println!("extend: {}", a); +} +``` + +# Alternatives + + * We just implement everything to accept iterators. It does lead to a simpler, + but less powerful, interface. + * Felix Klock (pnkfelix) suggested an alternative name of `Pushable` instead of + `Extendable`. This trait would also provide a `.push()` method for adding a + single element. + +# Unresolved questions + + * This RFC should be revisited if/when we gain associated items. It could + reduce some of the function declaration syntactic overhead. From a7efb5362ede40cf7efa774f267c52e5edc239c9 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Fri, 21 Mar 2014 10:24:42 -0700 Subject: [PATCH 2/4] Convert RFC into a general `Iterable` trait family proposal. --- 0000-into_iterator.md | 83 ----------------------- 0000-iterable.md | 152 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 152 insertions(+), 83 deletions(-) delete mode 100644 0000-into_iterator.md create mode 100644 0000-iterable.md diff --git a/0000-into_iterator.md b/0000-into_iterator.md deleted file mode 100644 index c90ab94c3bb..00000000000 --- a/0000-into_iterator.md +++ /dev/null @@ -1,83 +0,0 @@ -- Start Date: 2014-03-20 -- RFC PR #: (leave this empty) -- Rust Issue #: (leave this empty) - -# Summary - -Add an `IntoIterator` trait that allows a function to consume both an iterator -and a value that can be converted into an iterator. - -# Motivation - -We have some unnecessary redundancy in some of our collection APIs: - - * `Vec::push_all` is designed to take one `Vec` and merge it into another. - * `Extendable::extend` takes an Iterator and merges it into a value. - * `vec::append` copies and merges one `Vec` with anther `Vec`. - -# Detailed design - -This redundancy can be eliminated with a simple trait: - -``` -trait IntoIterator> { - fn into_iterator(self) -> Iter; -} -``` - -Here is how it would be used with `Vec`: - -``` -use std::vec_ng::{Vec, MoveItems}; - -impl IntoIterator> for MoveItems { - fn into_iterator(self) -> MoveItems { self } -} - -impl IntoIterator> for Vec { - fn into_iterator(self) -> MoveItems { self.move_iter() } -} -``` - -Almost every value and Iterator will have the same implementation so this could -be a good use case for a macro. - -Here is a demonstration on how they would be used: - -``` -trait MyExtendable { - fn my_extend, IntoIter: IntoIterator>(&mut self, x: IntoIter); -} - -impl MyExtendable for Vec { - fn my_extend, IntoIter: IntoIterator>(&mut self, x: IntoIter) { - let mut iter = x.into_iterator(); - let (size, _) = iter.size_hint(); - self.reserve_additional(size); - - for x in iter { - self.push(x); - } - } -} - -fn main() { - let mut a = Vec::new(); - a.my_extend(vec!(4, 5, 6)); - a.my_extend(vec!(7, 8, 9).move_iter()); - println!("extend: {}", a); -} -``` - -# Alternatives - - * We just implement everything to accept iterators. It does lead to a simpler, - but less powerful, interface. - * Felix Klock (pnkfelix) suggested an alternative name of `Pushable` instead of - `Extendable`. This trait would also provide a `.push()` method for adding a - single element. - -# Unresolved questions - - * This RFC should be revisited if/when we gain associated items. It could - reduce some of the function declaration syntactic overhead. diff --git a/0000-iterable.md b/0000-iterable.md new file mode 100644 index 00000000000..108349552a2 --- /dev/null +++ b/0000-iterable.md @@ -0,0 +1,152 @@ +- Start Date: 2014-03-20 +- RFC PR #: (leave this empty) +- Rust Issue #: (leave this empty) + +# Summary + +Add an `Iterable` family of traits that will allow a function to consume both +an iterator or a value that can be converted into an iterator. + +# Motivation + +We have some unnecessary redundancy in some of our collection APIs: + + * `Vec::push_all` is designed to take one `Vec` and merge it into another. + * `Extendable::extend` takes an Iterator and merges it into a value. + * `vec::append` copies and merges one `Vec` with anther `Vec`. + +# Detailed design + +This redundancy can be eliminated with a simple trait: + +``` +/// Any type that implements `Iterable` can be iterated over with the +/// iterator `I` to yield values of type `T`. Because of Rusts move semantics, +/// this means that `self` needs to be taken by value, which for moving types +/// means turning `self` into a iterator. +trait Iterable> { + fn into_iter(self) -> I; + + fn map<'r, B>(self, f: 'r |A| -> B) -> iter::Map<'r, A, B, I> { + self.into_iter().map(f) + } + + fn collect>(self) -> B { + iter::FromIterator::from_iterator(&mut self.into_iter()) + } + + // ... all old Iterator adapters that take `self` and make sense + // to provide on a data structure directly +} +``` + +This trait is implementable by both values and iterators. Values would opt-in +to implementing `Iterable`, where we would move all `.move_iter()`-style +methods to impls of `Iterable`: + +``` +use std::vec_ng::{Vec, Items, MutItems, MoveItems}; + +impl Iterable> for Vec { + fn into_iter(self) -> MoveItems { + self.move_iter() + } +} +``` + +Iterators would now be required to implement `Iterable`: + +``` +trait Iterator: Iterable { + ... +} + +impl Iteratable> for MoveItems { + fn into_iter(self) -> MoveItems { self } +} +``` + +Since every Iterator will have the same implementation so this could be a good +use case for a macro. + +Additionally, we would add two similar traits to handle returning references: + +``` +trait RefIterable<'a, A, I: iter::Iterator> { + fn refs(&'a self) -> I; +} + +trait MutIterable<'a, A, I: iter::Iterator> { + fn mut_refs(&'a mut self) -> I; +} +``` + +We also could support more optimal iterators for collections of `Pod`s + +``` +/// Automatically implemented for all `RefIterable<&A>` with `A: Pod` +trait PodIterable<'a, A: Pod, I: iter::Iterator> { + fn values(&'a self) -> Values; +} + +// Automatically implement for all `RefIterable<&A>` with `A: Pod` +impl<'a, T: Pod, RefIter: iter::Iterator<&'a T>, Iter: RefIterable<'a, &'a T, RefIter>> + PodIterable<'a, &'a T, RefIter> for Iter { + fn values(&'a self) -> Values { Values { iter: self.refs() } } +} + +///////////////////////////////////////////////////////////////////////////// + +struct Values { iter: I } +impl<'a, T: Pod, I: iter::Iterator<&'a T>> iter::Iterator for Values { + fn next(&mut self) -> Option { self.iter.next().map(|x| *x) } + fn size_hint(&self) -> (uint, Option) { self.iter.size_hint() } +} +impl<'a, T: Pod, I: iter::DoubleEndedIterator<&'a T>> iter::DoubleEndedIterator for Values { + fn next_back(&mut self) -> Option { self.iter.next_back().map(|x| *x) } +} +impl<'a, T: Pod, I: iter::ExactSize<&'a T>> iter::ExactSize for Values {} +``` + +Finally, here is a demonstration of using this trait to reimplement `Extendable`: + +``` +trait Extendable { + fn extend, Iter: Iterable>(&mut self, x: Iter); +} + +impl Extendable for Vec { + fn extend, Iter: Iterable>(&mut self, iter: Iter) { + let mut iter = iter.into_iter(); + let (size, _) = iter.size_hint(); + self.reserve_additional(size); + + for x in &mut iter { + self.push(x); + } + } +} + +fn main() { + let mut a = Vec::new(); + a.my_extend(vec!(4, 5, 6)); + a.my_extend(vec!(7, 8, 9).move_iter()); + println!("extend: {}", a); +} +``` + +# Alternatives + + * We just implement everything to accept iterators. It does lead to a simpler, + but less powerful, interface. + * Felix Klock (pnkfelix) suggested an alternative name of `Pushable` instead of + `Extendable`. This trait would also provide a `.push()` method for adding a + single element. + +# Unresolved questions + + * This RFC should be revisited if/when we gain associated items. It could + reduce some of the function declaration syntactic overhead. + * This RFC should be revisited if we modify the coherence rules to allow impls like + `impl Iterable for I { ... }` while still allowing for other + impls of `Iterable`. From 78bf4e4557b8e622079836a72b4e3d32b5ffa9ae Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Fri, 21 Mar 2014 10:47:11 -0700 Subject: [PATCH 3/4] Add syntax highlighting --- 0000-iterable.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/0000-iterable.md b/0000-iterable.md index 108349552a2..44bb8d6ddb4 100644 --- a/0000-iterable.md +++ b/0000-iterable.md @@ -19,7 +19,7 @@ We have some unnecessary redundancy in some of our collection APIs: This redundancy can be eliminated with a simple trait: -``` +```rust /// Any type that implements `Iterable` can be iterated over with the /// iterator `I` to yield values of type `T`. Because of Rusts move semantics, /// this means that `self` needs to be taken by value, which for moving types @@ -44,7 +44,7 @@ This trait is implementable by both values and iterators. Values would opt-in to implementing `Iterable`, where we would move all `.move_iter()`-style methods to impls of `Iterable`: -``` +```rust use std::vec_ng::{Vec, Items, MutItems, MoveItems}; impl Iterable> for Vec { @@ -56,7 +56,7 @@ impl Iterable> for Vec { Iterators would now be required to implement `Iterable`: -``` +```rust trait Iterator: Iterable { ... } @@ -71,7 +71,7 @@ use case for a macro. Additionally, we would add two similar traits to handle returning references: -``` +```rust trait RefIterable<'a, A, I: iter::Iterator> { fn refs(&'a self) -> I; } @@ -83,7 +83,7 @@ trait MutIterable<'a, A, I: iter::Iterator> { We also could support more optimal iterators for collections of `Pod`s -``` +```rust /// Automatically implemented for all `RefIterable<&A>` with `A: Pod` trait PodIterable<'a, A: Pod, I: iter::Iterator> { fn values(&'a self) -> Values; @@ -110,7 +110,7 @@ impl<'a, T: Pod, I: iter::ExactSize<&'a T>> iter::ExactSize for Values {} Finally, here is a demonstration of using this trait to reimplement `Extendable`: -``` +```rust trait Extendable { fn extend, Iter: Iterable>(&mut self, x: Iter); } From 5e0ac0f673d7f606c026356b50026e38609cfdf2 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Fri, 21 Mar 2014 10:56:03 -0700 Subject: [PATCH 4/4] Flesh out the `PodIterable` section, and add an example --- 0000-iterable.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/0000-iterable.md b/0000-iterable.md index 44bb8d6ddb4..76ba3e5d455 100644 --- a/0000-iterable.md +++ b/0000-iterable.md @@ -81,7 +81,8 @@ trait MutIterable<'a, A, I: iter::Iterator> { } ``` -We also could support more optimal iterators for collections of `Pod`s +We also could support more optimal iterators for collections of `Pod`s. This +allows users to replaces calls of `x.refs().map(|x| *x)` with `x.values()`: ```rust /// Automatically implemented for all `RefIterable<&A>` with `A: Pod` @@ -108,7 +109,7 @@ impl<'a, T: Pod, I: iter::DoubleEndedIterator<&'a T>> iter::DoubleEndedIterator< impl<'a, T: Pod, I: iter::ExactSize<&'a T>> iter::ExactSize for Values {} ``` -Finally, here is a demonstration of using this trait to reimplement `Extendable`: +Finally, here is a demonstration of using these traits to reimplement `Extendable`: ```rust trait Extendable { @@ -129,8 +130,10 @@ impl Extendable for Vec { fn main() { let mut a = Vec::new(); - a.my_extend(vec!(4, 5, 6)); - a.my_extend(vec!(7, 8, 9).move_iter()); + a.my_extend(vec!(1, 2)); + a.my_extend(vec!(3, 4).into_iter()); + a.my_extend(vec!(5, 6).refs().map(|x| x.clone())); + a.my_extend(vec!(7, 8).values()); println!("extend: {}", a); } ```