Decoupling ownership from vector - rust

I'm creating factory methods for objects with shared references. The compiler cannot see that the objects from a Vec are not referenced outside the local scope, and that the newly created objects are not linked to the original objects.
How do I get around this issue, what am I missing?
#[derive(Debug)]
pub struct A {}
pub struct B<'b> {
a: &'b A,
}
impl<'b> B<'b> {
pub fn new(a: &'b A) -> B {
B { a: a }
}
pub fn combine(&self, _: &B) -> B {
B::new(self.a)
}
}
pub fn main() {
let a: A = A {};
let mut v1: Vec<B> = vec![];
v1.push(B::new(&a));
v1.push(B::new(&a));
let mut v2: Vec<B> = vec![];
{
let b1 = &v1[0]; // << Mutable borrow occurs here - why?
let b2 = &v1[1];
let c = b1.combine(&b2);
v2.push(c)
}
v1.clear(); // Error: Cannot borrow due to mutable borrow above
println!("{:?}", v2[0].a);
}
error[E0502]: cannot borrow `v1` as mutable because it is also borrowed as immutable
--> src/main.rs:32:5
|
27 | let b1 = &v1[0]; // << Mutable borrow occurs here - why?
| -- immutable borrow occurs here
...
32 | v1.clear(); // Error: Cannot borrow due to mutable borrow above
| ^^^^^^^^^^ mutable borrow occurs here
33 | println!("{:?}", v2[0].a);
| -- immutable borrow later used here
No, sorry, I still do not quite get it.
Here is an even simpler example, without vectors:
let a:A = A { };
let mut b1 = B::new(&a);
let mut b2 = B::new(&a);
let c = &b1.combine(&b2);
// ^^^ This creates a mutable reference to b1. How to avoid?
b1 = B::new(&a);
b2 = B::new(&a);
println!("{:?}",c.a);
For some reason, the method call on the object will make the compiler assume that I have a reference to the object, despite c having no reference to b1. How do I get around that?
How can I declare the combine()-method to be immutable?

Related

How do I pass a mutable reference to a method on an object that belongs to that reference?

I have a struct instance A that belongs to a struct instance B. I will need to do some processing on this data by calling the parent.
struct A {
val : u8
}
struct B {
data : u8,
a : A
}
impl A {
pub fn process(&mut self, b : &mut B) {
println!("Processing {} - {}", b.data, self.val);
//do stuff with val and data...
}
}
impl B {
pub fn process(&mut self) {
self.a.process(self);
}
}
fn main() {
let mut b = B {
data : 0,
a : A {
val : 3
}
};
b.process();
}
When I try to call b.process(), I'm getting the following failure:
error[E0499]: cannot borrow `self.a` as mutable more than once at a time
--> src/main.rs:47:9
|
47 | self.a.process(self);
| ^^^^^^^-------^----^
| | | |
| | | first mutable borrow occurs here
| | first borrow later used by call
| second mutable borrow occurs here
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/main.rs:47:24
|
47 | self.a.process(self);
| ---------------^^^^-
| | | |
| | | second mutable borrow occurs here
| | first borrow later used by call
| first mutable borrow occurs here
All of this works fine when mutable references aren't needed.
So my question is, what's the right way to do this when I need this type of relationship between the two structs?
In Rust you can either have a single mutable reference or multiple immutable references, or, put differently: single writer / multiple readers.
let mut a = 0; // Only mutable variables can be written to
let a1 = &a;
let a2 = &a; // Readers can be many
// This is an error:
let a3 = &mut a; // You cannot write to `a` while it is borrowed for reading
print!("{} {} {}", a1, a2, a3)
let mut a = 0;
let a1 = &mut a; // You can have a single writer
// This is an error:
let a2 = &mut a; // But there can be only one
// This is also an error:
let a3 = &a; // You cannot read while `a` can be written to
print!("{} {} {}", a1, a2, a3)
Following this logic we can make some observations on the code
impl A {
// this implies that both self and B can change
pub fn process(&mut self, b: &mut B) {
println!("Processing {} - {}", b.data, self.val);
//do stuff with val and data...
}
pub fn process_changes_a(&mut self, b: &B) {
println!("Processing {} - {}", b.data, self.val);
}
pub fn process_changes_b(&self, b: &mut B) {
println!("Processing {} - {}", b.data, self.val);
}
}
impl B {
pub fn process(&mut self) {
// it's possible to use clones to work around this
// however it's probably better to refactor the logic
// let's see what happens when using clones
let mut tmp_self = self.clone();
let mut tmp_a = self.a.clone();
// this can modify both self.a and tmp_self
self.a.process(&mut tmp_self);
// now self and tmp_self could be different
// does self need to have the value of the &mut B?
// note: this clone is only necessary for
// the other examples to compile
*self = tmp_self.clone();
// or does only self.a need to change?
tmp_a.process(self);
self.a = tmp_a;
// or should the original self.a stay the same?
self.data = tmp_self.data;
}
pub fn process_changes_a(&mut self) {
// you still need a clone of self.a
// otherwise A::process_changes_a could
// modify a through self while reading b.a
let mut tmp_a = self.a.clone();
tmp_a.process_changes_a(self);
self.a = tmp_a;
}
pub fn process_changes_b(&mut self) {
// you still need a clone of self.a
// otherwise A::process_changes_b could
// modify a through b.a while reading self
let tmp_a = self.a.clone();
tmp_a.process_changes_b(self);
}
pub fn process_on_self(&mut self) {
// if you need to modify both self and self.a
// it might be best to have the method directly on B
println!("Processing {} - {}", self.data, self.a.val);
}
}
The problem really comes from the fact that A::process(&mut self, b: &mut B) doesn't know that both self and b.a reference the same value when called from B and expects them to be different. You can make it work by using clones or copies, however it is probably unnecessary.
Personally, I'd probably try to move the logic of process() entirely to B. In your example A depends on B, but also B depends on A. This would make it so that only B depends on A, which makes things simpler.
You can't that's against Rusts aliasing rules, you'd have two mutable references to the A one direct and one indirectly through B. If you really wanted to you could use interior mutability (RefCell, Mutex, ...) but as kaya3 pointed out your suggested implementation seems rather strange even from an OO viewpoint. If it needs a B anyways, I'd just implement it on B diretly without the indirection.

Trouble understanding immutable and mutable borrows in vector indexing operations

I just started out with Rust. I have some trouble understanding mutable and immutable borrows with respect to this snippet of code. Here is the code I am testing.
fn main() {
let mut list = vec![1,2,3,4,5,6];
let i = 2;
list[list[i]] = list[list[i-1]];
}
On compiling this, I get the following error:
error[E0502]: cannot borrow `list` as immutable because it is also borrowed as mutable
--> src/main.rs:4:7
|
4 | list[list[i]] = list[list[i-1]];
| -----^^^^----
| | |
| | immutable borrow occurs here
| mutable borrow occurs here
| mutable borrow later used here
error: aborting due to previous error
When I replace the snippet above with this code instead,
fn main() {
let mut list = vec![1,2,3,4,5,6];
let i = 2;
let index = list[i];
list[index] = list[list[i-1]];
}
the code compiles and executes fine.
My question is why is the compiler not flagging this as an error like this?
5 | list[index] = list[list[i-1]];
| --------------| |
| | | immutable borrow occurs here
| | immutable borrow occurs here
| mutable borrow occurs here
| mutable borrow later used here
Isin't the right hand side of the assignment an immutable borrow? Why only flag the first code snippet as an error?
Does Rust have something like happens-before or sequenced before relationship in C++ which ensures that the immutable borrow on the right hand side is sequenced before the mutable borrow on the left hand side and hence it is not an error?
If the answer to the previous question is yes, then why can't the compiler sequence list[list[i]] internally as let tmp = list[i]; list[tmp]=...?
Here is some code that demonstrates the same issue, but a bit simplified.
fn main() {
let mut list: Vec<usize> = vec![1,2,3,4,5,6];
let i: usize = 2;
let place: &mut usize = &mut list[list[i]];
*place = 3;
}
Evidently, the compiler is doing something like this:
fn main() {
let mut list: Vec<usize> = vec![1,2,3,4,5,6];
let i: usize = 2;
// mutable borrow of list starts
let r: &mut Vec<usize> = &mut list;
// immutable borrow of list starts
let q: usize = list[i];
// immutable borrow of list ends
// mutable borrow of r starts
let place: &mut usize = &mut r[q];
// place is a mutable borrow derived from r
*place = 3;
// place is dropped, mutable borrow of r ends
// r is dropped, mutable borrow of list ends
}
This code works fine:
fn main() {
let mut list: Vec<usize> = vec![1,2,3,4,5,6];
let i: usize = 2;
let q: usize = list[i]; // immutable borrow begins and ends
let place: &mut usize = &mut list[q]; // mutable borrow begins
*place = 3; // mutable borrow ends
}

When is a reference being 'used' in non-lexical lifetimes?

struct Object {
alive: bool,
name: String,
}
impl Object {
// the comments are what I thought the compiler was supposed to give
fn test(&mut self) {
let alive = &mut self.alive; // seems like there is mutable borrow here
self.name = String::from("dead"); // another mutable borrow
*alive = false; // mutable borrow later used here
}
}
fn print(x: &Object) {
println!("Hello {:?}", x);
}
A non-lexical lifetime is supposed to be when a reference stops living after it's last use. I am confused on what that use is.
alive is a mutable borrow to self.alive and then self is used to do self.name = String::from("dead");. After this it looks like alive is used again in *alive = false. Except this code compiles.
If I change the code to this:
fn test(&mut self) {
let alive = &mut self.alive;
print(self);
self.name = String::from("dead");
*alive = false;
}
then the code gives this error
error[E0502]: cannot borrow `*self` as immutable because it is also borrowed as mutable [10/58]
--> src/main.rs:45:15
|
44 | let alive = &mut self.alive;
| --------------- mutable borrow occurs here
45 | print(self);
| ^^^^ immutable borrow occurs here
46 | self.name = String::from("dead");
47 | *alive = false;
| -------------- mutable borrow later used here
. Does this mean that references are only 'used' when they are in functions and not when dereferenced with * or the dot notation? How does the first example compile even though it seems like the the reference scopes are overlapping?
Does this mean that references are only 'used' when they are in functions and not when dereferenced with * or the dot notation?
You are close. Non-lexical lifetimes aren't a factor here, but the borrow checker has more tricks up its sleeves. It knows that the fields of a struct are distinct objects and can be borrowed independently.
From the Rust Nomicon on Splitting Borrows:
It does understand structs sufficiently to know that it's possible to borrow disjoint fields of a struct simultaneously. So this works today:
struct Foo {
a: i32,
b: i32,
c: i32,
}
let mut x = Foo {a: 0, b: 0, c: 0};
let a = &mut x.a;
let b = &mut x.b;
let c = &x.c;
*b += 1;
let c2 = &x.c;
*a += 10;
println!("{} {} {} {}", a, b, c, c2);
So in your code, there can be exclusive references to both self.alive and self.name because borrow checker knows they aren't referencing the same object. Adding the print(self) needs to reference the whole self and conflicts with the borrow given to alive.

Why doesn't the lifetime of a mutable borrow end when the function call is complete?

I'm writing a bot for halite.io, and am having issues understanding some of the effects of borrowing. Here is the code that will not compile:
let scanLoc = hlt::types::Location {
x: oflow(coord.0 + l.x as i32, game_map.width),
y: oflow(coord.1 + l.y as i32, game_map.width),
};
let scan = game_map.get_site(scanLoc, types::STILL);
if (&scan.owner != id) | (scan.owner != 0u8) {
let ang = game_map.get_angle(l, scanLoc);
debug!("angle b/w: {}", ang);
return (l, 2);
}
This is the compiler error:
error[E0502]: cannot borrow `*game_map` as immutable because it is also borrowed as mutable
--> src/MyBot.rs:112:27
|
110 | let scan = game_map.get_site(scanLoc, types::STILL);
| -------- mutable borrow occurs here
111 | if (&scan.owner != id) | (scan.owner != 0u8) {
112 | let ang = game_map.get_angle(l, scanLoc);
| ^^^^^^^^ immutable borrow occurs here
...
116 | }
| - mutable borrow ends here
This is the code for the GameMap functions and struct:
#[derive(Clone, Debug)]
pub struct GameMap {
pub width: u16, // Number of columns.
pub height: u16, // Number of rows.
pub contents: Vec<Vec<Site>>,
}
impl GameMap {
pub fn in_bounds(&self, l: Location) -> bool {
// ...
}
pub fn get_distance(&self, l1: Location, l2: Location) -> u16 {
// ...
}
pub fn get_angle(&self, l1: Location, l2: Location) -> f64 {
// ...
}
pub fn get_location(&self, l: Location, d: u8) -> Location {
// ...
}
pub fn get_site(&mut self, l: Location, d: u8) -> &mut Site {
// ...
}
}
Why does Rust borrow the function mutably, and even if it is borrowing the function would it not return the borrow (ending the lifetime) when returning the result, so it would be available to borrow afterwards?
Editor's note: This specific problem has been solved by the introduction of non-lexical lifetimes.
Let's look at a tiny reproduction:
struct Site {
owner: u8,
}
struct GameMap {
site: Site,
}
impl GameMap {
fn do_anything(&self) {}
fn get_site(&mut self) -> &mut Site {
&mut self.site
}
}
fn main() {
let mut game_map = GameMap {
site: Site { owner: 0 },
};
let site = game_map.get_site();
game_map.do_anything();
}
error[E0502]: cannot borrow `game_map` as immutable because it is also borrowed as mutable
--> src/main.rs:22:5
|
21 | let site = game_map.get_site();
| -------- mutable borrow occurs here
22 | game_map.do_anything(); // Compiler error!
| ^^^^^^^^ immutable borrow occurs here
23 | }
| - mutable borrow ends here
Our GameMap only owns a single Site, but that's enough. The call to get_site returns a reference (in this case it happens to be mutable):
fn get_site(&mut self) -> &mut Site
Thanks to lifetime elision, this is the same as
fn get_site<'a>(&'a mut self) -> &'a mut Site
This means that the returned reference is allowed to point to something inside of GameMap (which it does). Then we keep that reference in a variable - site!
That means that we can no longer use any immutable references to game_map as they might have been (or will in the future be) invalidated by the changes that can be made to the map through the mutable reference:
At any given time, you can have either one mutable reference or any number of immutable references.
References must always be valid.
— The Rust Programming Language chapter on references and borrowing
Why does Rust borrow the function mutably, and even if it is borrowing the function would it not return the borrow (ending the lifetime) when returning the result, so it would be available to borrow afterwards?
Rust borrows your struct mutably because you are calling a method that requires a mutable reference (&mut self). That method then returns a mutable reference, transferring the borrow of the struct to the returned value. The borrow ends when the returned value goes out of scope.
So, how do you fix it? Probably the most flexible solution is to introduce a scope to constrain the mutable borrow:
let zhu_li_do_the_thing = {
let site = game_map.get_site();
site.owner == 5 || site.owner == 42
};
if zhu_li_do_the_thing {
game_map.do_anything();
}
Another is the same idea, but requires that you never store the borrow in a variable at all. Thus the mutable borrow doesn't last beyond that statement:
if game_map.get_site().owner == 42 {
game_map.do_anything();
}
It's common for idiomatic Rust code to have foo and foo_mut variants of a method, for when you don't need mutability. This may not help if you need to mutate game_map while the immutable borrow of site is still outstanding.
fn get_site(&self) -> &Site {
&self.site
}
fn get_site_mut(&mut self) -> &mut Site {
&mut self.site
}
let site = game_map.get_site();
if site.owner == 5 || site.owner == 42 {
game_map.do_anything();
}
See also:
Returning a reference from a HashMap or Vec causes a borrow to last beyond the scope it's in?
What are non-lexical lifetimes?

Borrow errors for multiple borrows

I am implementing an in-place recursive parser in rust and I am getting some borrow errors. The code snippet reproduces the problem although it is not very useful
use std::vec::Vec;
struct MyBorrows<'a> {
val : &'a mut i32
}
impl <'a> MyBorrows<'a> {
fn new(v : &'a mut i32) -> MyBorrows<'a> {
MyBorrows { val : v }
}
}
fn main() {
let mut my_val = 23;
let mut my_vec : Vec<Box<MyBorrows>> = Vec::new();
my_vec.push(Box::new(MyBorrows::new(&mut my_val)));
for i in [1..4].iter() {
let mut last : &mut Box<MyBorrows> = my_vec.last_mut().unwrap();
let mut new_borrow = Box::new(MyBorrows::new(last.val));
my_vec.push(new_borrow);
}
}
This gives me the following error:
error[E0499]: cannot borrow `my_vec` as mutable more than once at a time
--> test.rs:20:9
|
18 | let mut last : &mut Box = my_vec.last_mut().unwrap();
| ------ first mutable borrow occurs here
19 | let mut new_borrow = Box::new(MyBorrows::new(last.val));
20 | my_vec.push(new_borrow);
| ^^^^^^ second mutable borrow occurs here
21 | }
22 | }
| - first borrow ends here
error: aborting due to 3 previous errors
In my real case, the vector is used as a stack to reference deeper and deeper components of the struct I am parsing into. This is common pattern I use for general purpose parsing in C++ which I am trying to replicate in Rust but I am having problems. Any help will be appreciated.
What you are trying to do is unsound. It looks like you are attempting to create multiple MyBorrows which all mutably borrow the same value, and have them all alive at once (in the vector). Such setups are exactly what Rust is designed to prevent, as that's how data races occur.
What you might instead want to do is immutably borrow the value a bunch, which is legal. So after cleaning up the unnecessary mutable borrows, I've reduced the problem to:
struct MyBorrows<'a> {
val : &'a i32
}
impl <'a> MyBorrows<'a> {
fn new(v : &'a i32) -> MyBorrows<'a> {
MyBorrows { val : v }
}
}
fn main() {
let my_val = 23;
let mut my_vec = vec![];
my_vec.push(Box::new(MyBorrows::new(&my_val)));
for _ in 1..4 {
let last = my_vec.last().unwrap();
let new_borrow = Box::new(MyBorrows::new(last.val));
my_vec.push(new_borrow);
}
}
You get a slightly different error now:
error[E0502]: cannot borrow `my_vec` as mutable because it is also borrowed as immutable
--> test.rs:18:9
|
16 | let last = my_vec.last().unwrap();
| ------ immutable borrow occurs here
17 | let new_borrow = Box::new(MyBorrows::new(last.val));
18 | my_vec.push(new_borrow);
| ^^^^^^ mutable borrow occurs here
19 | }
| - immutable borrow ends here
error: aborting due to previous error
This one is trickier, and you have to realize what is going on when you call my_vec.last() -- it's returning a reference to existing memory in the Vec, precluding anything else from touching the Vec. Currently in Rust, this reference lives until the end of the current block. To get around this, encase the mutable borrow in its own block scope:
fn main() {
let my_val = 23;
let mut my_vec = vec![];
my_vec.push(Box::new(MyBorrows::new(&my_val)));
for _ in 1..4 {
let new_borrow;
{
let last = my_vec.last().unwrap();
new_borrow = Box::new(MyBorrows::new(last.val));
}
my_vec.push(new_borrow);
}
}
Now the mutable borrow ends before the push occurs, and the lifetimes work. Hopefully in the future, we will get non-lexical lifetimes added to the language, so the compiler can figure out that my first example is actually safe.

Resources