You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Have for pattern in iter not borrow the iterator #8372
let mut iter = range(1, 10);
for i in iter {
printfln!(i);
// error: cannot borrow `iter` as mutable more than once at a time
printfln!(iter.next());
}
The above currently fails, but I think it should be valid and equivalent to:
let mut iter = range(1, 10);
loop { match iter.next() { None => break, Some(i) => {
printfln!(i);
printfln!(iter.next());
}}
In other words, the for loop should only borrow the iterator long enough to call next(), leaving the loop body free to use it.
I understand that this might not be possible when a more complex expression is used as the iterator. The for loop needs to evaluate the expression once and keep the result in an anonymous variable, thus borrowing. Maybe there could be a special case when the iterator expression is "simple" enough: a variable, struct field access, etc?
This means implementing it as more than a simple parser feature. It's not possible to check the type of the passed in variable at the moment and decide whether a temporary is needed.
@thestingerfor is likely to need to be a non-parser feature anyway: it is currently duck-typed, and gives horrible error messages. (As I'm sure you know.)
@thestinger what you say might still be true, but this is the type of AST node (eg. identifier) for the iterator, not Rust type (eg. std::vec::VecIterator.)
Also, this is a "nice to have", but not blocking because I can just use loop with match. I even have a macro for it:
// Work around "error: cannot borrow `iter` as mutable more than once at a time"
// when using a normal for loop.
macro_rules! for_iter(
($iter: expr, $pattern: pat, $loop_body: expr) => (
loop {
match $iter.next() { None => break, Some($pattern) => $loop_body }
}
);
)
// Work around "error: cannot borrow `iter` as mutable more than once at a time"
// when using a normal for loop.
macro_rules! for_iter(
($iter: ident, $pattern: pat, $loop_body: expr) => (
loop {
match $iter.next() { None => break, Some($pattern) => $loop_body }
}
);
)
Maybe there could be a special case when the iterator expression is "simple" enough: a variable, struct field access, etc?
It seems to me that there is precedent for language constructs to act specially when the expression in question is an lvalue, c.f. match; that would be a natural choice here.
@blake2-ppc could you write the expansion you are thinking of? (I'm specifically wondering how that would allow for something like for x in foo.iter() { ... }, while also allowing for x in bar { bar.next() } to do the right thing.)
As far as blocking 1.0 goes, it won't bother me personally if this doesn't get fixed until after. But it might be confusing and offputting to newcomers who already have a lot to learn about ownership. (I know I've invented a few new things to say after "why the ...?" beacuse of this issue.)
Might it be possible to detect the situation and emit a hint about the workaround?
Now that while let is an option, I am not sure if this should be
fixed. Particularly since for was defined to invoke IntoIterator
on its argument -- and thus in a sense takes ownership of its argument
(though not quite, is that a backwards compat hazard @aturon?). If you
plan to mess with the iterator itself during iteration, it seems to me
that using a distinct kind of loop is a good indication of this (I
certainly don't expect it when I see a for loop).
On Thu, Dec 18, 2014 at 07:46:54PM -0800, Stephen Mosher wrote:
As far as blocking 1.0 goes, it won't bother me personally if this doesn't get fixed until after. But it might be confusing and offputting to newcomers who already have a lot to learn about ownership. (I know I've invented a few new things to say after "why the ...?" beacuse of this issue.)
Might it be possible to detect the situation and emit a hint about the workaround?
Reply to this email directly or view it on GitHub: #8372 (comment)
Now that while let is an option, I am not sure if this should be
fixed. Particularly since for was defined to invoke IntoIterator
on its argument -- and thus in a sense takes ownership of its argument
(though not quite, is that a backwards compat hazard @aturon?). If you
plan to mess with the iterator itself during iteration, it seems to me
that using a distinct kind of loop is a good indication of this (I
certainly don't expect it when I see a for loop).
On Thu, Dec 18, 2014 at 07:46:54PM -0800, Stephen Mosher wrote:
As far as blocking 1.0 goes, it won't bother me personally if this
doesn't get fixed until after. But it might be confusing and offputting to
newcomers who already have a lot to learn about ownership. (I know I've
invented a few new things to say after "why the ...?" beacuse of this
issue.)
Might it be possible to detect the situation and emit a hint about the
workaround?
Reply to this email directly or view it on GitHub: #8372 (comment)
—
Reply to this email directly or view it on GitHub #8372 (comment).
#20790 implemented the new for-loops that take the iterator by value, so this issue can't be fixed (without changing the semantics in a backwards incompatible way). This should be closed.
Activity
thestinger commentedon Aug 7, 2013
This means implementing it as more than a simple parser feature. It's not possible to check the type of the passed in variable at the moment and decide whether a temporary is needed.
huonw commentedon Aug 7, 2013
@thestinger
foris likely to need to be a non-parser feature anyway: it is currently duck-typed, and gives horrible error messages. (As I'm sure you know.)SimonSapin commentedon Aug 7, 2013
@thestinger what you say might still be true, but this is the type of AST node (eg. identifier) for the iterator, not Rust type (eg.
std::vec::VecIterator.)SimonSapin commentedon Aug 7, 2013
Also, this is a "nice to have", but not blocking because I can just use
loopwithmatch. I even have a macro for it:bluss commentedon Aug 7, 2013
Your macro should probably take an ident, not an expression since it doesn't work well with expressions!
SimonSapin commentedon Aug 7, 2013
Good point, @blake2-ppc.
huonw commentedon Nov 15, 2013
triage, no progress.
pnkfelix commentedon Nov 21, 2013
It would be good to decide what we're going to do about these things. (This and #8649)
But its not clear whether it should block 1.0.
nikomatsakis commentedon Nov 25, 2013
cc me
ezyang commentedon Dec 17, 2013
It seems to me that there is precedent for language constructs to act specially when the expression in question is an lvalue, c.f.
match; that would be a natural choice here.emberian commentedon Jun 11, 2014
Another painful example:
is good, but:
is not.
bluss commentedon Jun 11, 2014
Is it possible to migrate to a for-by-value by recommending users who need the reference behaviour to useIterator::by_ref()?huonw commentedon Jun 11, 2014
@blake2-ppc could you write the expansion you are thinking of? (I'm specifically wondering how that would allow for something like
for x in foo.iter() { ... }, while also allowingfor x in bar { bar.next() }to do the right thing.)pczarn commentedon Jul 30, 2014
Solved by #15809
SimonSapin commentedon Jul 30, 2014
@pczarn, indeed it is, thanks for the heads up! Updated for language/lib changes, the initial test case now works as expected:
23 remaining items
Stebalien commentedon Dec 18, 2014
You can now just use
while let:It's not perfect but but better than using a macro (IMHO).
SimonSapin commentedon Dec 18, 2014
Oooh, this is much nicer indeed. In particular since there is only one nesting level of
{}. Thanks for the tip!smosher commentedon Dec 19, 2014
As far as blocking 1.0 goes, it won't bother me personally if this doesn't get fixed until after. But it might be confusing and offputting to newcomers who already have a lot to learn about ownership. (I know I've invented a few new things to say after "why the ...?" beacuse of this issue.)
Might it be possible to detect the situation and emit a hint about the workaround?
nikomatsakis commentedon Dec 21, 2014
Now that
while letis an option, I am not sure if this should befixed. Particularly since
forwas defined to invokeIntoIteratoron its argument -- and thus in a sense takes ownership of its argument
(though not quite, is that a backwards compat hazard @aturon?). If you
plan to mess with the iterator itself during iteration, it seems to me
that using a distinct kind of loop is a good indication of this (I
certainly don't expect it when I see a
forloop).On Thu, Dec 18, 2014 at 07:46:54PM -0800, Stephen Mosher wrote:
emberian commentedon Dec 21, 2014
I used to be annoyed about this a ton, but now that we have
while let,I agree.
On Sat, Dec 20, 2014 at 9:08 PM, Niko Matsakis notifications@github.com
wrote:
http://octayn.net/
SimonSapin commentedon Dec 21, 2014
I still kinda wish this was fixed, but I understand @nikomatsakis’s argument and I don’t mind as much with the
while letalternative.japaric commentedon Jan 31, 2015
#20790 implemented the new for-loops that take the iterator by value, so this issue can't be fixed (without changing the semantics in a backwards incompatible way). This should be closed.
SimonSapin commentedon Jan 31, 2015
Fair enough. I’m happy with the
while let Some(value) = iterator.next() {trick.Don't suggest using a for loop if the iterator is used in the loop body
Don't suggest using a for loop if the iterator is used in the loop body
Don't suggest using a for loop if the iterator is used in the loop body
Auto merge of rust-lang#8372 - tamaroning:unwrap_used, r=llogiq