Mutable borrow in a loop - reference

I have the following code:
struct Baz {
x: usize,
y: usize,
}
struct Bar {
baz: Baz,
}
impl Bar {
fn get_baz_mut(&mut self) -> &mut Baz {
&mut self.baz
}
}
struct Foo {
bar: Bar,
}
impl Foo {
fn foo(&mut self) -> Option<&mut Baz> {
for i in 0..4 {
let baz = self.bar.get_baz_mut();
if baz.x == 0 {
return Some(baz);
}
}
None
}
}
Rust Playground
It fails to compile with:
error[E0499]: cannot borrow `self.bar` as mutable more than once at a time
--> src/main.rs:23:23
|
23 | let baz = self.bar.get_baz_mut();
| ^^^^^^^^ mutable borrow starts here in previous iteration of loop
...
29 | }
| - mutable borrow ends here
However, if I return Some(baz.x) from Foo::foo (and change the return type to Option<usize>), the code compiles. This makes me believe the problem is not with the loop even though the compiler seems to indicate so. More specifically, I believe the local mutable reference baz would go out of scope at the next iteration of the loop, causing this to be a non-problem. What is the lifetime problem with the above code?
The following questions are similar:
Mutable borrow in loop
Linking the lifetimes of self and a reference in method
Cannot borrow as mutable more than once at a time in one code - but can in another very similar
However, they deal with explicitly declared lifetimes (and specifically these explicit lifetimes are part of the answer). My code omits these lifetimes so removing them is a non-solution.

It does not work because returning a borrowed value extends the borrow to the end of the function.
See here for some useful details.
This works with non-lexical lifetimes with the 1.27 nightly version:
#![feature(nll)]
struct Baz {
x: usize,
y: usize,
}
// ...
The non-lexical lifetimes RFC explains the actual working of lifetimes:
Problems arise however when you have a reference that spans multiple statements. In that case, the compiler requires the lifetime to be the innermost expression (which is often a block) that encloses both statements, and that is typically much bigger than is really necessary or desired
rustc nightly 1.28
As pointed out by #pnkfelix, the non-lexical lifetimes implementation starting from nightly 1.28 no longer compiles the above code.
There is however a long-term plan to (re)-enable a more powerful NLL analysis.

Related

Borrowing parts of structs without RefCell

According to this question, it is not possible to borrow parts of a struct, only the entire struct. This makes sense, however I would not expect the following code (playground) to compile, which it does:
struct Struct (u32, u32);
fn foo(a: &mut u32, b: &u32) {
}
fn main() {
let mut s = Struct ( 1, 2 );
foo(&mut s.0, &s.1);
}
Why does this work?
Additionally, is there any way to get the compiler to make the same differentiation between borrowing members when some indirection is introduced via. a method, without using a RefCell or other run-time checking. See (playground):
struct Struct (u32, u32);
impl Struct {
fn a(&mut self) -> &mut u32 {
&mut self.0
}
fn b(&self) -> &u32 {
&self.1
}
}
fn foo(a: &mut u32, b: &u32) {
}
fn main() {
let mut s = Struct ( 1, 2 );
foo(s.a(), s.b());
}
At the moment this fails with:
error[E0502]: cannot borrow `s` as immutable because it is also borrowed as mutable
--> src/main.rs:18:16
|
18 | foo(s.a(), s.b());
| --- ----- ^^^^^ immutable borrow occurs here
| | |
| | mutable borrow occurs here
| mutable borrow later used by call
I realise this is a bit of an obtuse example, my real case involves borrowing a number of members so the borrowing methods' implementations are more complex. There are still no members which are borrowed by both functions however.
Rust very deliberately does not extend its inference powers across function boundaries. This helps in making code more forwards compatible as you only need to keep the signature consistent and not its internals.
For example, consider your own code. If you decided later that a() should actually return a reference to self.1 then it would break all the code that used a() and b() together like you did. With the current limitations, you can easily change what field the reference comes from and not have to worry about breaking anyone.
Unfortunately, this makes what you want to do impossible.
I suggest giving the problem a higher level look. Do a() and b() really belong together on the same struct? Would it perhaps be better to split the two fields into their own structs?
Ideally, when you take a mutable reference to a struct, you would be using all (or most) of the struct, and there would be no need for someone else to be using that struct.

Borrow mutable reference in an impl block with generic lifetime parameter

I'm trying to write a simple code which generates elements based on a random number generator, for which I have a working code here. Now I wanted to add a reference from each struct to the next in the list. The basic idea is that each struct has a state and an optional reference to another struct with the same lifetime.
#[derive(Copy, Clone, Debug)]
enum MyState
{
On,
Off
}
#[derive(Copy, Clone, Debug)]
struct MyStruct<'a>
{
state: MyState,
next_struct : Option<&'a MyStruct<'a>>,
}
The generic lifetime parameter 'a is a new addition to basically mark the fact that all structs have the same lifespan.
Then I have a simple associated function creating random structs with no reference, but now my impl block must also have the generic lifetime parameter.
// stand-in for replacement struct from rand crate
struct RandomGenerator {
random_number : f64,
}
impl<'a> MyStruct<'a>
{
fn random(r : & mut RandomGenerator) -> MyStruct
{
if r.random_number > 0.5 {
r.random_number -= 0.1;
return MyStruct{state : MyState::On, next_struct : None};
}
r.random_number = 1.0 as f64;
MyStruct{state : MyState::Off, next_struct : None}
}
}
Finally I'm trying to generate my elements in a loop
fn main() {
let mut grid = Vec::<MyStruct>::new();
let mut rng = RandomGenerator{random_number : 0.5};
for _i in 0..GRID_SIZE*GRID_SIZE // const GRID_SIZE : usize = 10;
{
grid.push(MyStruct::random(&mut rng));
}
println!("{:#?}", grid);
}
The full code is here. While the first version worked as expected, the second version fails to compile with
error[E0499]: cannot borrow `rng` as mutable more than once at a time
--> src/main.rs:43:60
|
43 | grid.get_mut(i).unwrap().push(MyStruct::random(&mut rng));
| ^^^^^^^^ `rng` was mutably borrowed here in the previous iteration of the loop
error: aborting due to previous error
Looking at similar questions most of them deal with self references, which seems to be more complicated than what I'm doing here, since I'm passing an unrelated object just for one function call, and it appears to be burrowed for longer..
I tried adding a generic lifetime 'b to the random method, which is then used only for the RNG mutable, but this does not work either. Why would adding a generic lifetime parameter that is not even used in the signature of the function changes the borrowing behaviour? What is the correct way to write this?
Here's a working version of your function (playground):
impl<'a> MyStruct<'a>
{
fn random(r: &mut RandomGenerator) -> MyStruct<'a>
{ // ^^^^
This is due to lifetime elision:
If there is exactly one input lifetime position (elided or not), that lifetime is assigned to all elided output lifetimes.
Since you didn't annotate the lifetime tied to MyStruct, the compiler inferred it must be linked to the lifetime of r.

Why is this borrow still "active"?

This is a simplified example of something I've encountered:
trait Bla<'a> {
fn create(a: &'a Foo) -> Self;
fn consume(self) -> u8;
}
struct Foo;
impl Foo {
fn take(&mut self, u: u8) {}
}
struct Bar {
foo: Foo,
}
impl Bar {
fn foobar<'a, 'b, B: Bla<'b>>(&'a mut self)
where 'a: 'b {
let u = {
// immutable borrow occurs here
// type annotation requires that `self.foo` is borrowed for `'b`
let foo: &'b Foo = &self.foo;
let b = B::create(foo);
b.consume()
};
// error[E0502]: cannot borrow `self.foo` as mutable because it is also borrowed as immutable
self.foo.take(u);
}
}
Why is self.foo still considered to be borrowed even after exiting the block it was borrowed on, with everything that used the borrow also dropped?
The data might flow to another place.
To understand why the compiler is correct that the immutable borrow might still exist, consider the following implementation of Bla that is valid:
#![feature(once_cell)]
// The data stored in this global static variable exists for the entirety of runtime.
static REFS: SyncLazy<Mutex<Vec<&'static Foo>>> = SyncLazy::new(|| Mutex::new(vec![]));
struct Bad;
impl Bla<'static> for Bad {
fn create(a: &'static Foo) -> Self {
// The reference can go somewhere other than `Self`!
REFS.lock().unwrap().push(a);
Bad
}
fn consume(self) -> u8 {
// Even if `self` is consumed here,
// `self` doesn't necessarily destory the immutable borrow.
0
}
}
When your generic foobar function accepts any valid implementation of Bla, a valid implementation might take a &'static borrow that guarantees the borrow to last for the entire runtime. Therefore, it is an error because consume does not guarantee that the immutable borrow goes away.
You are probably looking for the for<> syntax as that will allow the Bad implementation to exist but will disallow anyone from calling foobar with Bad:
impl Bar {
fn foobar<B: for<'b> Bla<'b>>(&mut self) {
let u = {
let foo: &Foo = &self.foo;
let b = B::create(foo);
b.consume()
};
self.foo.take(u);
}
}
fn main() {
Bar::foobar::<Bad>(&mut Bar { foo: Foo })
// ^ error: implementation of `Bla` is not general enough
// | `Bad` must implement `Bla<'0>`, for any lifetime `'0`...
// | ...but it actually implements `Bla<'static>`
}
If this isn't the case, you might have to provide more implementation details rather than an example causing the diagnostic error.
Normally, when you don't specify your own lifetime, the lifetime of an immutable borrow to a variable ends when the variable goes out of scope. But in your code, you are specifying an explicit lifetime 'b of the immutable borrow.
To the borrow checker, the only thing known about the lifetime 'b is that it is a subset of 'a (due to where 'a: 'b). In particular, the borrow checker will not assume that the scope of the immutable borrow ends at }, because nothing of that sort is specified about 'b.
The compiler actually says this out loud:
// type annotation requires that self.foo is borrowed for 'b
Summary
Why is self.foo still considered to be borrowed even after exiting the block it was borrowed on, with everything that used the borrow also dropped?
Because the lifetime you specify does not end when the block ends. The borrow checker does not care about that some variables related to the borrow goes out of scope.

How does borrowing Box<Trait> contents work?

I have this minimal example code:
use std::borrow::BorrowMut;
trait Foo {}
struct Bar;
impl Foo for Bar {}
fn main() {
let mut encryptor: Box<Foo> = Box::new(Bar);
encrypt(encryptor.borrow_mut());
}
fn encrypt(encryptor: &mut Foo) { }
but it fails with this error:
error: `encryptor` does not live long enough
--> src/main.rs:11:1
|
10 | encrypt(encryptor.borrow_mut());
| --------- borrow occurs here
11 | }
| ^ `encryptor` dropped here while still borrowed
|
= note: values in a scope are dropped in the opposite order they are created
The kind people at #rustbeginners found that I have to dereference the box to get the contents, and then borrow the contents. Like this:
trait Foo {}
struct Bar;
impl Foo for Bar {}
fn main() {
let mut encryptor: Box<Foo> = Box::new(Bar);
encrypt(&mut *encryptor);
}
fn encrypt(encryptor: &mut Foo) { }
It works, but I don't understand it.
Why do I need to dereference first? What is the error trying to say? Normally it isn't an error that a value is dropped at the end of the function.
Apparently it's not just me who doesn't understand how this works; an issue has been filed.
Let's start with a change that allows the code to work:
fn encrypt(encryptor: &mut (Foo + 'static)) { }
The important difference is the addition of + 'static to the trait object - the parens are just needed for precedence.
The important thing to recognize is that there are two lifetimes present in &Foo:
a lifetime for the reference itself: &'a Foo
a lifetime that represents all the references inside the concrete value that the trait abstracts: &(Foo + 'b).
If I'm reading the RFCs correctly, this was introduced by RFC 192, and RFC 599 specified reasonable defaults for the lifetimes. In this case, the lifetimes should expand like:
fn encrypt(encryptor: &mut Foo) { }
fn encrypt<'a>(encryptor: &'a mut (Foo + 'a)) { }
On the other end of the pipe, we have a Box<Foo>. Expanded by the rules of the RFC, this becomes Box<Foo + 'static>. When we take a borrow of it, and try to pass it to the function, we have an equation to solve:
The lifetime inside the trait object is 'static.
The function takes a reference to a trait object.
The lifetime of the reference equals the lifetime of references inside the trait object.
Therefore, the reference to the trait object must be 'static. Uh oh!
The Box will be dropped at the end of the block so it certainly isn't static.
The fix with explicit lifetimes allows the lifetime of the reference to the trait object to differ from the lifetime of the references inside the trait object.
If you needed to support a trait object with internal references, an alternate is to do something like:
fn encrypt<'a>(encryptor: &mut (Foo + 'a)) { }
True credit for this explanation goes to nikomatsakis and his comment on GitHub, I just expanded it a bit.

Unable to infer lifetime for borrow expression when using a trait with an explicit lifetime

use std::io::BufReader;
struct Foo {
buf: [u8, ..10]
}
trait Bar<'a> {
fn test(&self, arg: BufReader<'a>) {}
}
impl<'a, T: Bar<'a>> Foo {
fn bar(&'a mut self, t: T) {
t.test(BufReader::new(&self.buf));
let b = &mut self.buf;
}
fn baz(&self, t: T) {
t.test(BufReader::new(&self.buf));
}
}
fn main() {}
The code above fails to compile, with the error message:
lifetimes.rs:17:31: 17:40 error: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
lifetimes.rs:17 t.test(BufReader::new(&self.buf));
^~~~~~~~~
lifetimes.rs:16:5: 18:6 help: consider using an explicit lifetime parameter as shown: fn baz(&'a self, t: T)
lifetimes.rs:16 fn baz(&self, t: T) {
lifetimes.rs:17 t.test(BufReader::new(&self.buf));
lifetimes.rs:18 }
error: aborting due to previous error
However, if I add the named lifetime parameter, I cannot mutable borrow the buf field after calling test, as seen in fn bar. Commenting out the fn baz and trying to compile results in:
lifetimes.rs:13:22: 13:30 error: cannot borrow `self.buf` as mutable because it is also borrowed as immutable
lifetimes.rs:13 let b = &mut self.buf;
^~~~~~~~
lifetimes.rs:12:32: 12:40 note: previous borrow of `self.buf` occurs here; the immutable borrow prevents subsequent moves or mutable borrows of `self.buf` until the borrow ends
lifetimes.rs:12 t.test(BufReader::new(&self.buf));
^~~~~~~~
lifetimes.rs:14:6: 14:6 note: previous borrow ends here
lifetimes.rs:11 fn bar(&'a mut self, t: T) {
lifetimes.rs:12 t.test(BufReader::new(&self.buf));
lifetimes.rs:13 let b = &mut self.buf;
lifetimes.rs:14 }
^
error: aborting due to previous error
My understanding of this is that by adding the named lifetime 'a to the &'a mut self parameter, the reference taken by BufReader has a lifetime as long as the self reference is valid, which is until the end of the function. This conflicts with the mutable borrow of self.buf on the line after.
However, I am not sure why I need the named lifetime parameter on the self. It seems to me that the BufReader reference should be able to only exist for the lifetime of the t.test method call. Is the compiler complaining because the self.buf borrow must be ensured to live only as long as the &self borrow? How would I go about doing that while still only borrowing it for the lifetime of the method call?
Any help in going about fixing this problem and understanding more about the semantics here would be much appreciated!
Update
So I am still looking into this problem, and I have found this test case and this issue that show basically what I am trying to do. I would very much like to understand why the error pointed to by the test case link is an error.
I can see in the issue rustc output that attempts to point out what the error is, but I am having trouble understanding what exactly it is trying to say.
Removing all explicit lifetimes also works. I've found that I only add lifetimes when I'm sure I need them (i.e. to specifiy that two lifetimes should intersect at a given point which can't be known to the compiler).
I'm not sure exactly what you're going for, but this compiles (on rustc 0.13.0-nightly (cc19e3380 2014-12-20 20:00:36 +0000)).
use std::io::BufReader;
struct Foo {
buf: [u8, ..10]
}
trait Bar {
fn test(&self, arg: BufReader) {}
}
impl<T: Bar> Foo {
fn bar(&mut self, t: T) {
t.test(BufReader::new(&self.buf));
let b = &mut self.buf;
}
fn baz(&self, t: T) {
t.test(BufReader::new(&self.buf));
}
}
Edit
I'm going to copy-edit my comment here:
I originally thought that adding a lifetime or generic parameter to the trait / struct / enum was a shorthand for putting it on every method in the trait, but I was wrong. My current understanding is that you add a lifetime to the trait / struct / enum when that item needs to participate in the lifetime, likely because it is storing a reference with that lifetime.
struct Keeper<'a> {
counts: Vec<&'a i32>,
}
impl<'a> Keeper<'a> {
fn add_one(&mut self, count: &'a i32) {
if *count > 5 {
self.counts.push(count);
}
}
fn add_two<'b>(&mut self, count: &'b i32) -> i32 {
*count + 1
}
}
fn main() {
let mut cnt1 = 1;
let mut cnt2 = 2;
let mut k = Keeper { counts: Vec::new() };
k.add_one(&cnt1);
k.add_two(&cnt2);
// cnt1 += 1; // Errors: cannot assign to `cnt1` because it is borrowed
cnt2 += 1; // Just fine
println!("{}, {}", cnt1, cnt2)
}
Here, we've added a lifetime to Keeper because it might store the reference it is given. The borrow checker must assume that the reference is stored for good when we call add_one, so once we call that method, we can no longer mutate the value.
add_two, on the other hand, creates a fresh lifetime that can only be applied to that function invocation, so the borrow checker knows that once the function returns, it is the One True Owner.
The upshot is, if you need to store a reference, then there's nothing you can do at this level. Rust can't make sure you are safe, and that's something it takes seriously.
However, I bet you don't need to store the reference. Move the <'a, T: Bar<'a>> from the impl to the fn and you'll be good to go.
Said another way: I bet you should never have impl<A> if your trait or struct don't require it. Put the generics on the methods instead.
Original
This compiles, but I'm not 100% sure it does what you intended:
impl Foo {
fn baz<'a, T: Bar<'a>>(&'a self, t: T) {
t.test(BufReader::new(&self.buf));
}
}
I fell into this trap myself, so I'll paste what I was told:
Everything in the impl block is parameterized. I've actually never
seen type parameters added to impl blocks themselves that aren't part
of the trait or type definition. It's far more common to parameterize
the individual methods that need it.
Perhaps other comments / answers can help explain in further detail.

Resources