Uh oh!
There was an error while loading. Please reload this page.
Introduce the IntoIterator trait and reimplement for-loops to use it - #20790
Conversation
rust-highfive
commented
Jan 9, 2015
(rust_highfive has picked a reviewer for you, use r? to override) |
huonw
commented
Jan 9, 2015
Can we do this without expanding in the front end? |
japaric
commented
Jan 9, 2015
@huonw@nikomatsakis was interested in an implementation that used the frontend (hence this prototype) |
huonw
commented
Jan 9, 2015
Also, expanding to include |
japaric
commented
Jan 9, 2015
(I think @aturon and @nikomatsakis mainly want to measure the size of the fallout and the change in ergonomics of these new for-loop semantics before commiting to it. This implementation is minimal work to measure that. We can come up with a better implementation if we decide to actually do this.) |
There was a problem hiding this comment.
Could some loops like this be altered to:
for ch inself.iter.by_ref(){/* ... */}That may avoid consuming the entire iterator.
There was a problem hiding this comment.
Actually, if it helps in basically all cases, I wonder if we could spec it like this...
There was a problem hiding this comment.
I had forgotten about by_ref()! I think we can use that instead of most (all?) the while lets.
Actually, if it helps in basically all cases, I wonder if we could spec it like this...
You mean using by_ref() in the for loop expansion?
japaric
commented
Jan 10, 2015
Updated to use the |
nikomatsakis
commented
Jan 10, 2015
Some thoughts:
|
jroesch
commented
Jan 10, 2015
@japaric and @nikomatsakis As a fan of desugaring as much as possible I think this seems like a good idea. If error messages become a problem you could use a similar scheme to what they do with Pyret where you provide a tag (either in some table or directly on the AST) for which rewrite rule you used, and then utilize that information when reporting errors by re-sugaring it then pretty printing. I would be happy to help explore such a scheme if the error reporting suffers. |
japaric
commented
Jan 12, 2015
Updated PR with @nikomatsakis suggestions ( I've collected some error messages from 3 cfail tests related to for-loops:
structMyStruct{x:isize,y:isize,}implMyStruct{fnnext(&mutself) -> Option<isize>{Option::Some(self.x)}}fnmain(){letmut bogus = MyStruct{x:1,y:2,};for x in bogus {//~^ old-ERROR has type `MyStruct` which does not implement the `Iterator` trait//~^^ new-ERROR the trait `iter::Iterator` is not implemented for the type `MyStruct`}}The error message changed its wording but the meaning is the same.
fnmain(){for&1i8//~^ old-ERROR refutable pattern in `for` loop binding//~^^ new-ERROR non-exhaustive patterns: `Some(&_)` not coveredin[1i8].iter(){}}The message is more obscure now.
fnmain(){let x = () + ();//~ ERROR binary operation// this shouldn't have a flow-on error:// japaric: and it doesn't with the either version of for loopsfor _ in x {}}Behavior remains the same. |
There was a problem hiding this comment.
Now that we have cfg_attr, could this be #![cfg_attr(stage0, allow(unused_mut))]? Anything with the string "stage0" in it is a pretty easy flag for something to clean out when dealing with snapshots.
nikomatsakis
commented
Jan 13, 2015
@japaric and I were talking on IRC. My feeling is that the error in this example: fnmain(){for&1i8//~^ old-ERROR refutable pattern in `for` loop binding//~^^ new-ERROR non-exhaustive patterns: `Some(&_)` not coveredin[1i8].iter(){}}is actually better. I doubt most "lay people" know what a "refutable pattern" is. (I personally have to work out from first principles which is "irrefutable" and which is "refutable".) But having a concrete counter example seems immediately understandable. It might be better still to combine the two messages: |
huonw
commented
Jan 13, 2015
@nikomatsakis I think introducing the |
IntoIterator trait and reimplement for-loops to use itIntoIterator trait and reimplement for-loops to use itjaparic
commented
Jan 23, 2015
This PR is ready! (passed re: error message on refutable patterns, I decide to reuse the old message/diagnostic code, we can customize it later if desired. |
japaric
commented
Jan 26, 2015
rebased and added tests for issues that new for loops fix. Also fixed a recursive call that the new |
japaric
commented
Jan 26, 2015
Just a heads up, until #21637 gets fixed, we won't be able to use the fnconcat<I:IntoIterator>(it:I) -> Stringwhere <I::IterasIterator>::Item:Str{unimplemented!();} |
alexcrichton
commented
Jan 30, 2015
@bors: retry |
As per [RFC rust-lang#235][rfc], you can now do: [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0235-collections-conventions.md#intoiterator-and-iterable ``` rust let mut v = vec![1]; // iterate over immutable references for x in &v { assert_eq!(x, &1); } // iterate over mutable references for x in &mut v { assert_eq!(x, &mut 1); } // iterate over values, this consumes `v` for x in v { assert_eq!(x, 1); } ``` [breaking-change]s For loops now "consume" (move) the iterator, this breaks iterating over mutable references to iterators, and also breaks multiple iterations over the same iterator: ``` rust fn foo(mut it: &mut Iter) { // `Iter` implements `Iterator` for x in it { .. } //~ error: `&mut Iter` doesn't implement Iterator } fn bar() { for x in it { .. } //~ note: `it` moved here for x in it { .. } //~ error: `it` has been moved } ``` Both cases can be fixed using the `by_ref()` adapter to create an iterator from the mutable reference: ``` rust fn foo(mut it: &mut Iter) { for x in it.by_ref() { .. } } fn bar() { for x in it.by_ref() { .. } for x in it { .. } } ``` This PR also makes iterator non-implicitly copyable, as this was source of subtle bugs in the libraries. You can still use `clone()` to explictly copy the iterator. Finally, since the for loops are implemented in the frontend and use global paths to `IntoIterator`, `Iterator` and `Option` variants, users of the `core` crate will have to use add an `std` module to the root of their crate to be able to use for loops: ``` rust #![no_std] extern crate core; fn main() { for x in 0..10 {} } #[doc(hidden)] mod std { // these imports are needed to use for-loops pub use core::iter; pub use core::option; } ``` --- r? @nikomatsakis@aturon cc rust-lang#18424closesrust-lang#18045
bors
commented
Jan 30, 2015
⌛ Testing commit b9a9030 with merge e47284b... |
alexcrichton
commented
Jan 30, 2015
@bors: retry |
bors
commented
Jan 31, 2015
⌛ Testing commit b9a9030 with merge e513946... |
bors
commented
Jan 31, 2015
💔 Test failed - auto-linux-64-opt |
alexcrichton
commented
Jan 31, 2015
@bors: retry |
bors
commented
Jan 31, 2015
⌛ Testing commit b9a9030 with merge 581a5c8... |
bors
commented
Jan 31, 2015
💔 Test failed - auto-linux-64-x-android-t |
alexcrichton
commented
Jan 31, 2015
@bors: retry |
bors
commented
Jan 31, 2015
⌛ Testing commit b9a9030 with merge 692c620... |
bors
commented
Jan 31, 2015
💔 Test failed - auto-linux-32-opt |
alexcrichton
commented
Jan 31, 2015
@bors: retry |
bors
commented
Jan 31, 2015
⌛ Testing commit b9a9030 with merge 72eab3e... |
Removes `Copy` from `ops::Range` (`a..b`) and `ops::RangeFrom` (`a..`) [breaking-change] --- I forgot about these two in #20790, this PR also adds `Clone` to the `Peekable` adapter which used to be `Copy`able. r? @nikomatsakis or anyone
taralx
commented
Feb 3, 2015
The RFC didn't mention this "mod std" business, and I'm a bit uncomfortable with it. Why not directly access the core crate? |
japaric
commented
Feb 3, 2015
If you mean expanding to
You already have to use the |
japaric
commented
Feb 3, 2015
alexchandel
commented
Feb 4, 2015
The relevant section of the Rust Reference ought to be updated to reflect this, cc @steveklabnik |
As per RFC #235, you can now do:
[breaking-change]s
For loops now "consume" (move) the iterator, this breaks iterating over mutable references to iterators, and also breaks multiple iterations over the same iterator:
Both cases can be fixed using the
by_ref()adapter to create an iterator from the mutable reference:This PR also makes iterator non-implicitly copyable, as this was source of subtle bugs in the libraries. You can still use
clone()to explictly copy the iterator.Finally, since the for loops are implemented in the frontend and use global paths to
IntoIterator,IteratorandOptionvariants, users of thecorecrate will have to use add anstdmodule to the root of their crate to be able to use for loops:r? @nikomatsakis@aturon
cc #18424
closes#18045