Can we assign value to `a` if it is borrowed? - rust

this is simple code which shows error cannot assign to a because it is borrowed assi gnment to borrowed a occurs here. Can it be possible to assign value if it is borrowed?
fn main() {
let mut a = 20;
let b = &a;
a = 20;
println!("{}, {}", a, b);
}

Not without interior mutability.
Disallowing mutation of a value that is borrowed prevents many different kinds of bugs. For example, you cannot push onto a Vec while you have a shared reference to a value in the Vec. This seems arbitrary, but if pushing causes an internal reallocation, previously-dispensed references would become dangling.
Here's what the interior mutability approach would look like:
use std::cell::Cell;
fn main() {
let a = Cell::new(20);
let b = &a;
a.set(10);
println!("{}, {}", a.get(), b.get());
}
Note a doesn't even have to be declared mut, because cells can be mutated through a shared reference.

Rust enforces "multiple readers or single writer" rule at compile time. As long as there is mutable reference to a value you cannot use the owner until the mutable reference goes away. Similarly as long as there is multiple shared references to value not even it's owner can modify it. For example, this would compile.
fn main() {
let mut a = 20;
{
let b = &a;
println!("{}", b);
} // Shared reference goes out of scope here
a = 20;
println!("{}", a);
}

Related

Assign mutable reference to immutable reference

This code doesn't compile. But it fails on the last line marked Err, not the line marked Ok. Why can we assign a mutable reference to an immutable reference type but not use it after the assignment?
fn main() {
let mut x = 10;
let mut y = 20;
let mut r = &x;
r = &mut y; //Ok
*r = 30; //Err
}
Why can we ... not use it after the assignment?
The variable r is an immutable reference of type &i32; it does not have mutable access to the referenced value. So it makes sense the compiler would reject your attempt to assign through it.
Why can we assign a mutable reference to an immutable reference type ...?
Why wouldn't you be able to downgrade a mutable reference into an immutable one? The latter is a strict subset of the former. If you were asking about the technicalities instead of the practicalities, its because &mut T to &T is a supported coercion.
If we add explicit types to your code as inferred by the compiler:
fn main() {
let mut x: i32 = 10;
let mut y: i32 = 20;
let mut r: &i32 = &x;
r = &mut y; //Ok
*r = 30; //Err
}
We see that r has type &i32 and not &mut i32, so of course we can't use r to modify the referenced value.
Why can we still do r = &mut y? Simply because we can always use a &mut reference anywhere a & reference is expected (because &mut T implements Deref<Target=T>, allowing coercion to happen).

Rust: one mutable reference to a particular piece of data at a time?

I am noob to Rust and wanted to solidify my understanding of mutable reference in Rust.
fn mutate_me(st: &mut String)-> usize {
st.push_str(" mutated.");
st.len()
}
When I try using any one of either x or mutable reference r1 there is no compilation error.
fn main() {
let mut x = String::from("random");
let r1 = &mut x;
println!("{}", x);
}
This also work without any compilation error.
fn main() {
let mut x = String::from("random");
let r1 = &mut x;
println!("{}", mutate_me(r1));
}
But the one below fails as I tried using both of them.
fn main() {
let mut x = String::from("random");
let r1 = &mut x;
println!("{}", mutate_me(r1));
println!("{}", x);
println!("{}", *r1);
}
Does this imply that for mutable reference, whichever tried using it next first becomes valid and the other one invalid?
As a complement to #ChayimFriedman answer. Usually (not always) you have to work around the borrowing and flow of your program using scopes, so that things are used and dropped to liberate outer ones. For example your third case could be transformed as follows:
fn main() {
let mut x = String::from("random");
let res = {
let r1 = &mut x;
println!("{}", r1);
mutate_me(r1)
};
println!("{}", res);
println!("{}", x);
}
Playground
From the moment you borrow something to the last usage of the reference, the reference is considered alive for borrowing. Accessing an object while a mutable reference to it is alive is an error.
In your first example, you don't use r1 (it is immediately dropped), so the region of code where you can use x is between the two statements let r1 = &mut x; and let r1 = &mut x;, meaning... zero code.
In the second example you never use x, so in the code region x is invalid to use - between the declaration of r1 and its use - x is never actually used. Everything is fine.
The problem is in the third example, when you use x in the "invalid range". You can remove the println!("{}", mutate_me(r1)); - it doesn't matter.
The compiler points on these three important points: where the reference was created, when it's being used later, and where you perform the invalid access (this is called the "three-points models" in the NLL RFC):
error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
--> src/main.rs:4:20
|
3 | let r1 = &mut x;
| ------ mutable borrow occurs here
4 | println!("{}", x);
| ^ immutable borrow occurs here
5 | println!("{}", *r1);
| --- mutable borrow later used here
Playground.

Rust language : immutable borrow and mutable borrow error (2 cases) [duplicate]

After reading about Rust's scopes and references, I wrote a simple code to test them.
fn main() {
// 1. define a string
let mut a = String::from("great");
// 2. get a mutable reference
let b = &mut a;
b.push_str(" breeze");
println!("b = {:?}", b);
// 3. A scope: c is useless after exiting this scope
{
let c = &a;
println!("c = {:?}", c);
}
// 4. Use the mutable reference as the immutable reference's scope
// is no longer valid.
println!("b = {:?}", b); // <- why does this line cause an error?
}
As far as I understand:
Immutables and mutables cannot be used simultaneously.
2 mutables of same object cannot exist.
But scoping can allow 2 mutable to exist as long as 2 mutables are not in
the same scope.
Expectation
In 3, c is created within a scope, and no mutables are used in it. Hence,
when c goes out of scope, it is clear that c will not be used anymore (as
it would be invalid) and hence b, a mutable reference, can be used safely in
4.
The expected output:
b = "great breeze"
c = "great breeze"
b = "great breeze"
Reality
Rust produces the following error:
error[E0502]: cannot borrow `a` as immutable because it is also borrowed as mutable
--> src/main.rs:12:17
|
6 | let b = &mut a;
| ------ mutable borrow occurs here
...
12 | let c = &a;
| ^^ immutable borrow occurs here
...
18 | println!("b = {:?}", b); // <- why does this line cause an error?
| - mutable borrow later used here
Inference
(This is just what I think is happening, and can be a fallacy)
It seems that no matter what, you cannot use any mutable references (b)
once an immutable reference (c) was made (or "seen" by the rust
compiler), whether in a scope or not.
This is much like:
At any given time, you can have either one mutable reference or any
number of immutable references.
This situation is similar to:
let mut a = String::from("great");
let b = &mut a;
b.push_str(" breeze");
println!("b = {:?}", b);
// ^ b's "session" ends here. Using 'b' below will violate the rule:
// "one mutable at a time"
// can use multiple immutables: follows the rule
// "Can have multiple immutables at one time"
let c = &a;
let d = &a;
println!("c = {:?}, d = {:?}", c, d);
println!("b = {:?}", b); // !!! Error
Also, as long as we are using immutable references, the original object
or reference becomes "immutable". As said in Rust Book:
We also cannot have a mutable reference while we have an immutable one.
Users of an immutable reference don’t expect the values to suddenly
change out from under them!
and
...you can have either one mutable reference...
let mut a = String::from("great");
let b = &mut a;
b.push_str(" breeze");
println!("b = {:?}", b);
let c = &b; // b cannot be changed as long as c is in use
b.push_str(" summer"); // <- ERROR: as b has already been borrowed.
println!("c = {:?}", c); // <- immutable borrow is used here
So this code above somewhat explains #Shepmaster's solution.
Going back to the original code and removing the scope:
// 1. define a string
let mut a = String::from("great");
// 2. get a mutable reference
let b = &mut a;
b.push_str(" breeze");
println!("b = {:?}", b);
// 3. No scopes here.
let c = &a;
println!("c = {:?}", c);
// 4. Use the mutable reference as the immutable reference's scope
// is no longer valid.
println!("b = {:?}", b); // <- why does this line cause an error?
Now it is clear why this code has an error. The rust compiler sees that
we are using a mutable b (which is a mutable reference of a,
therefore a becomes immutable) while also borrowing an immutable
reference c. I like to call it "no immutables in between".
Or we can also call it "un-sandwiching". You cannot have/use a mutable
between "immutable declaration" and "immutable use" and vice-versa.
But this still does not answer the question of why scopes fail here.
Question
Even after explicitly moving c into a scope, why does the Rust
compiler produce this error message?
Your question is why doesn't compiler allow c to refer to data which is already mutably borrowed. I for one would expect that to be disallowed to begin with!
But - when you comment out the very last println!(), the code compiles correctly. Presumably that's what led you to conclude that aliasing is allowed, "as long as mutables aren't in the same scope". I argue that that conclusion is incorrect, and here is why.
While it's true that there are some cases where aliasing is allowed for references in sub-scopes, it requires further restrictions, such as narrowing an existing reference through struct projection. (E.g. given a let r = &mut point, you can write let rx = &mut r.x, i.e. temporarily mutably borrow a subset of mutably borrowed data.) But that's not the case here. Here c is a completely new shared reference to data already mutably referenced by b. That should never be allowed, and yet it compiles.
The answer lies with the compiler's analysis of non-lexical lifetimes (NLL). When you comment out the last println!(), the compiler notices that:
b isn't Drop, so no one can observe a difference if we pretend it was dropped sooner, perhaps immediately after last use.
b is no longer used after the first println!().
So NLL inserts an invisible drop(b) after the first println!(), thereby allowing introduction of c in the first place. It's only because of the implicit drop(b) that c doesn't create a mutable alias. In other words, the scope of b is artificially shortened from what would be determined by purely lexical analysis (its position relative to { and }), hence non-lexical lifetime.
You can test this hypothesis by wrapping the reference in a newtype. For example, this is equivalent to your code, and it still compiles with the last println!() commented out:
#[derive(Debug)]
struct Ref<'a>(&'a mut String);
fn main() {
let mut a = String::from("great");
let b = Ref(&mut a);
b.0.push_str(" breeze");
println!("b = {:?}", b);
{
let c = &a;
println!("c = {:?}", c);
}
//println!("b = {:?}", b);
}
But, if we merely implement Drop for Ref, the code no longer compiles:
// causes compilation error for code above
impl Drop for Ref<'_> {
fn drop(&mut self) {
}
}
To explicitly answer your question:
Even after explicitly moving c into a scope, why does the Rust compiler produce this error message?
Because c is not allowed to exist alongside b to begin with, regardless of being an an inner scope. When it is allowed to exist is in cases where the compiler can prove that b is never used in parallel with c and it's safe to drop it before c is even constructed. In that case aliasing is "allowed" because there's no actual aliasing despite b "being in scope" - on the level of the generated MIR/HIR, it's only c that refers to the data.

When to use Rc vs Box?

I have the following code which uses both Rc and Box; what is the difference between those? Which one is better?
use std::rc::Rc;
fn main() {
let a = Box::new(1);
let a1 = &a;
let a2 = &a;
let b = Rc::new(1);
let b1 = b.clone();
let b2 = b.clone();
println!("{} {}", a1, a2); //=> 1 1
println!("{} {}", b1, b2); //=> 1 1
}
playground link
Rc provides shared ownership so by default its contents can't be mutated, while Box provides exclusive ownership and thus mutation is allowed:
use std::rc::Rc;
fn main() {
let mut a = Box::new(1);
let mut b = Rc::new(1);
*a = 2; // works
*b = 2; // doesn't
}
In addition Rc cannot be sent between threads, because it doesn't implement Send.
The bottom line is they are meant for different things: if you don't need shared access, use Box; otherwise, use Rc (or Arc for multi-threaded shared usage) and keep in mind you will be needing Cell or RefCell for internal mutability.
Looking at the example given in the description, I think the real question here is "when to use Rc versus &Box" (note the ampersand).
Both Rc and &Box store the underlying data on the heap, neither can be sent across threads, and both allow immutable sharing (demonstrated by the aforementioned example). However, the biggest difference is that Rc gives you a shared (immutable) owned value while with &Box you get a shared (immutable) reference.
In the Rc case, the underlying data will be dropped (freed/deallocated) whenever the last owner (whether the original one or any cloned one) gets dropped – that's the idea of reference counting. In the &Box case, however, there is only one owner: any shared references to it will become invalid immediately after the owner gets out of scope.
Said differently, contrary to a Rc::clone(), binding a variable to a new &Box (let a2 = &a; in the example) will not make it live any longer than it would otherwise.
As a concrete example, the following is valid:
use std::rc::Rc;
fn main() {
let rc_clone;
{
let rc = Rc::new(1);
rc_clone = rc.clone();
// rc gets out of scope here but as a "shared owner", rc_clone
// keeps the underlying data alive.
}
println!("{}", rc_clone); // Ok.
}
But this isn't:
fn main() {
let b_ref;
{
let b = Box::new(1);
b_ref = &b;
// b gets out of scope here and since it is the only owner,
// the underlying data gets dropped.
}
println!("{}", b_ref); // Compilation error: `b` does not live long enough.
}

Mysterious borrow scope extension

Why does the compiler reject this code:
struct S<'a> {
i: i32,
r: &'a i32,
}
fn main() {
let mut s = S{i: 0, r: &0};
{
let m1 = &mut s;
m1.r = &m1.i;
}
let m2 = &mut s;
}
The error is: "cannot borrow s as mutable more than once at a time" (first borrow: m1, second borrow: m2).
Why is the first borrow of s still alive after m1 goes out of scope?
I read about borrow scope extension beyond the scope of the original borrower. However, this always seemed to involve another borrower outside the scope of the original borrower that "took over" the original borrow, e.g. this code fails with the exact same error, which is clear to me:
fn main() {
let mut s = 0;
let r: &mut i32;
{
let m1 = &mut s;
r = m1;
}
let m2 = &mut s;
}
In the first example, if I replace m1.r = &m1.i; with m1.r = &dummy; (dummy defined as some &i32) or with let dummy = &m1.i;, the code compiles. The error occurs only if I store a reference to a field in another field of the borrowed struct. I don't see why this should extend the borrow beyond its scope.
My best guess as to what is wrong with the code is:
s.r's original lifetime is the whole of main,
when I assign a reference to m1.r it has to be that original lifetime, but &m1.i is only valid for as long as m1 lives.
But I might be wrong (the error message would be misleading then).
First note that
let mut s = S{i: 0, r: &0};
{
s.r = &s.i;
}
let m2 = &mut s;
Gives
cannot borrow `s` as mutable because `s.i` is also borrowed as immutable
Hopefully this should be clear - if a struct self-borrows then it is borrowed. This points out why any self-borrowing structure is basically useless - it cannot be moved (invalidating its own pointer) nor can and mutable reference be taken to it.
Next one needs to understand that immutable references from mutable references count as borrows into the mutable reference, so extend it. For example
let mut v = ();
let r1 = &(&mut v);
let r2 = &v;
gives
cannot borrow `v` as immutable because it is also borrowed as mutable
It's not clear if this is legally able to be a new borrow into the original structure, but it as-yet does not act as such.

Resources