-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
RFC for adding an Iterable
trait family
#17
Conversation
Is this not the same as an A motivation for So I am mostly curious if this proposal ends up being the same as Update: Ah, I remembered (slash reviewed some irc logs): the technical problem was that people wanted to have a single generic This rfc, as written, may still be the same as the idea of |
@pnkfelix: I sketched up what I think is a usable @erickt: Feel free to incoperate it into the RFC. |
@pnkfelix: I had in mind that this We could change I'm quite looking forward to the day when we can do @Kimundi: your list looks great. Do you see just one implementation of your |
IntoIterator
traitIterable
trait family
@erickt Also, note that because something like A few more thoughts:
|
``` | ||
|
||
Since every Iterator will have the same implementation so this could be a good | ||
use case for a macro. |
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.
or a deriving?
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.
Yeah, this would be a perfect fit for #[deriving(Iterable)]
, though it might be confusing because its only for Iterators
.
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.
Yuck. This is a really nasty hack, and people will forget a #[deriving(Iterable)]
from time to time, leaving it much less usable. The only reasonable solution is to automatically implement it, which probably requires function specialisation to be implemented (rust-lang/rust#7059). Would it be feasible for us to start looking in that direction rather than piling #[deriving]
upon #[deriving]
, line upon line, here a little, there a little?
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.
@chris-morgan Note that it is not possible to forget the Iterable
impl on iterators: Iterator<A>
inherits from Iterable<A, Self>
.
So all a deriving mode would enable is to easily provide the implementation as long as the coherence rules prohibit a automatic generic implementation:
#[deriving(Iterable)]
struct MyIter<A> { ... }
impl<A> Iterator<A> for MyIter<A> { ... }
instead of
struct MyIter<A> { ... }
impl<A> Iterator<A> for MyIter<A> { ... }
impl<A> Iterable<A, MyIter<A>> for MyIter<A> { fn into_iter(self) -> MyIter<A> { self } }
Because of its special status of only being for iterators themself, a different name than deriving
might be more appropriate though.
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 added a custom attribute syntax extension to my example gist https://gist.github.com/Kimundi/9683769.
It implements a #[iterable]
attribute that you'd need to put on every implementation of Iterator
like this:
#[iterable]
impl<T> Iterator<T> for MyIter<T> {
fn next(&mut self) -> Option<T> { ... }
}
It would expand to this trivial implementation:
impl<T> Iterator<T> for MyIter<T> {
fn next(&mut self) -> Option<T> { ... }
}
impl<T> Iterable<T, MyIter<T>> for MyIter<T> {
fn into_iter(self) -> MyIter<T> { self }
}
If the intention of For containers, one does not usually want to (or is able to) consume the container just to iterate over it. Even for iterators, it is sometimes useful to partially iterate over an iterator without consuming it. The current desugaring just mutably borrows the iterator. |
@zkamsler: This is a very good point. The current This duality is what allows todays I toyed around with a version of the
Then you can still get both behaviors by explicitly constructing a let iter = ...;
for_ng x in iter {
// ^ Calls iter.into_iter(), consuming it.
// The iterator is a type_of(iter)
...
}
for_ng x in iter {
// ^ move error
...
} let mut iter = ...;
for_ng x in &mut iter {
// ^ Calls (&mut iter).into_iter() -> calls iter.mut_iter().
// The iterator is a ByRef<type_of(iter)>
...
}
for_ng x in &mut iter {
// ^ Works
...
} This also works if you create the reference once, like I'd argue that the explicitness here is better than However, doing it this way has two big problems:
Now, the possible good news is that the only solution to the second problem is to make This would eliminate the need of I added my experiments with this to the gist here: https://gist.github.com/Kimundi/9683769. |
Found a simpler way to accomplish the behavior from my last post: Instead of adding implementations for
I just added one implementation for
Which would look like this in practice: for_ng x in iterator { ... } // takes iterator by value, making either a copy or a move, and advances it
for_ng x in &mut iterator { ... } // advances and mutates the iterator through the reference
for_ng x in iterable { ... } // takes iterable by value, constructs a iterator, and advances it Again, this can be found implemented in https://gist.github.com/Kimundi/9683769. |
Sorry I haven't gotten to this in awhile, but here are some thoughts of mine. With the system proposed in #48, it looks like we're going to enable It seems a little unfortunate to need all these new traits rather than just one |
For the sake of discussion, specifically addressing @alexcrichton's question about multiple traits, here's one possible design using a single trait:
And some example code showing it in action:
Notice that, at least as implemented here for vectors, the kind of iterator you get depends on how you refer to the vector:
One argument in favor of this design is: if my function wants to iterate over some elements of type |
Another issue for discussion: what should the return type of default methods like But one might expect instead that if I don't have a strong opinion here, but I wanted to raise the issue. |
I think I tried the approach of different impls for About
1.) has better composabilty, but is more complex in general about where methods are, while 2) Is simpler but has the problem that it doesn't compose. Or rather, it composes, but with hidden cost: |
@alexcrichton: Most of the design of the RFC originated in my prototype implementation further up in the thread, so I'll give a few basic justifications ;) Three of the four traits basically just exist to support
The names That being said, if I where to actually implement it in the libraries, I'd reuse the existing names at first to make it easier, so I'd consider a rename of them a different RFC. |
This RFC should consider the new naming conventions for (methods that return) iterators. |
I've posted a collections reform RFC that encompasses some of this proposal (but also points out why we probably don't want to do the whole thing). |
6357402
to
e0acdf4
Compare
I'm going to close this now that Thanks @erickt |
Add an
Iterable
family of traits that will allow a function to consume bothan iterator or a value that can be converted into an iterator.