Does dereference equal to a function call? - rust

What happens if I borrow a dereferenced pointer?
let a = some object;
let b = &a;
let c = &*b;
What object has c borrowed? Does the dereferencing op create a temporary object like a function's return value? How does it obey the borrowing rules.
I'm also confused about Box's mutable semantic.
let mut a = Box::new(8us)
*a = 1;
This code works just fine without something like Box::new_mut(). But
let mut a = &8us;
*a = 1;
An error occurs.

Quick answer: It depends.
Long answer: keep reading...
What happens if I borrow a dereferenced pointer?
If you check out the LLVM-IR that rust generates, you can see everything in fine detail:
let a = 8us;
let b = &a;
let c = &*b;
gets expanded to
let a;
// %a = alloca i64
let b;
// %b = alloca i64*
let c;
// %c = alloca i64*
a = 8us;
// store i64 8, i64* %a
b = &a;
// store i64* %a, i64** %b
let tmp = *b;
// %0 = load i64** %b
c = tmp;
// store i64* %0, i64** %c
now, llvm can easily optimize this stuff out. It gets more complicated once you implement traits like Deref on your own types. Then obviously a function call is involved, but most likely optimized out again, since you shouldn't be doing complicated stuff in the deref function.
What object has c borrowed?
c borrows a
Does the dereferencing op create a temporary object like a function's return value?
Nope, see above
How does it obey the borrowing rules.
*b behaves as if it were a. If you take a reference to it you get a reference to a.
To answer your second issue:
A Box owns the object it points to. Since you declared your Box to be mutable, you can take eithe a mutable reference or any number of non-mutable references to your object. This means when you dereference the Box rust decides, depending the situation, whether to automatically create a mutable box. In the case of the assignment, your deref'd box is on the left side of the assignment operator, therefor rust tries to get a mutable reference to the object.
If you give your variables types, this becomes more obvious:
let mut x = Box::new(8us);
{
let y : &usize = &*x;
}
{
let y : &mut usize = &mut *x;
*x = 99; // cannot assign to `*x` because it is borrowed
}

Related

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

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);
}

cannot assign to `value`, which is behind a `&` reference [duplicate]

Here are two function signatures I saw in the Rust documentation:
fn modify_foo(mut foo: Box<i32>) { *foo += 1; *foo }
fn modify_foo(foo: &mut i32) { *foo += 1; *foo }
Why the different placement of mut?
It seems that the first function could also be declared as
fn modify_foo(foo: mut Box<i32>) { /* ... */ }
If you're coming from C/C++, it might also be helpful to think of it basically like this:
// Rust C/C++
a: &T == const T* const a; // can't mutate either
mut a: &T == const T* a; // can't mutate what is pointed to
a: &mut T == T* const a; // can't mutate pointer
mut a: &mut T == T* a; // can mutate both
You'll notice that these are inverses of each other. C/C++ take a "blacklist" approach, where if you want something to be immutable you have to say so explicitly, while Rust takes a "whitelist" approach, where if you want something to be mutable you have to say so explicitly.
mut foo: T means you have a variable called foo that is a T. You are allowed to change what the variable refers to:
let mut val1 = 2;
val1 = 3; // OK
let val2 = 2;
val2 = 3; // error: re-assignment of immutable variable
This also lets you modify fields of a struct that you own:
struct Monster { health: u8 }
let mut orc = Monster { health: 93 };
orc.health -= 54;
let goblin = Monster { health: 28 };
goblin.health += 10; // error: cannot assign to immutable field
foo: &mut T means you have a variable that refers to (&) a value and you are allowed to change (mut) the referred value (including fields, if it is a struct):
let val1 = &mut 2;
*val1 = 3; // OK
let val2 = &2;
*val2 = 3; // error: cannot assign to immutable borrowed content
Note that &mut only makes sense with a reference - foo: mut T is not valid syntax. You can also combine the two qualifiers (let mut a: &mut T), when it makes sense.
The following natural language translation seems to clear things up for me...
let x = value;
x {binds immutably} to {immutable value}
let mut x = value;
x {binds mutably} to {possibly mutable value}
let x = &value;
x {binds immutably} to {a reference to} {immutable value}
let x = &mut value;
x {binds immutably} to {a reference to} {mutable value}
let mut x = &value;
x {binds mutably} to {a reference to} {immutable value}
let mut x = &mut value;
x {binds mutably} to {a reference to} {mutable value}
where
{binds mutably} means the binding can be reassigned
{mutable value} means the value's contents can change
To be able to mutate a value you need both a mutable binding and a mutable value
Note:
Reference mutability vs target mutability
A reference variable such as x, as in let x = &mut y, is a separate variable from the target variable y it is pointing to. In particular, x has its own location on the stack and mutability permissions. As such, if x is immutable, as it is here, then it cannot be reassigned to point to some other variable. That restriction is separate from the ability to mutate the target through it, as in *x = some_value; the target is a distinct variable with its own mutability permissions. However, if w is mutable, as in let mut w = &mut p, then it can indeed be reassigned to point to some other similarly typed variable: w = &mut z.
Mutable Variable of Reference Type
When you have
let mut x: &T = value;
This means that x is variable that refers to an instance of T, as if by storing the memory address of the T instance in x's value. This reference (i.e. the "memory address") is the subject of mutability in this context: x can be modified to refer to a different instance of T like this:
x = some_other_T_instance;
but the referant (i.e. the value of the T instance to which x refers) cannot be changed via x:
// Illegal
*x = a_different_value;
Immutable variable of Mutable Reference type
When you have
let x: &mut T = value;
This means that x is a variable that refers to a mutable instance of T. In this case, the referent (i.e. the actual value) is the subject of mutability. It can be modified through the reference like this
*x = some_other_value;
but the reference itself (i.e. the "memory address" in the variable x) cannot:
// illegal
x = a_different_value;

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.

Reborrowing of mutable reference

When I wondered how a mutable reference could move into a method, all the questions began.
let a = &mut x;
a.somemethod(); // value of a should have moved
a.anothermethod(); // but it works.
I've googled a lot. (really a lot)
And I've noticed that a mutable reference passed as a parameter to a function, always undergoes the following transformation. (which is called reborrowing)
fn test(&mut a) -> ();
let a = &mut x;
test(a); // what we write in code.
test(&mut *a); // the actual action in code.
So, I have googled more about "reborrowing", for its detail.
And this is what I've got.
In any of codes, x refers to an arbitrary data. I don't mention it because I don't think the type of it is important for discussion. (However, I used i32 in my own).
let a = &mut x;
let b = &mut *a; // a isn't available from now on
*a = blahblah; // error! no more access allowed for a
*b = blahblah; // I've wrote this code not to confuse you of the lifetime of b. If not mentioned, it always live till the scope ends.
let a = &mut x;
{
let b = &*a;
// *a = blahblah in this scope will throw an error, just like above case.
}
*a = blahblah; // but this works.
So alright. It's quite interesting. It seems like b borrows not only x but also a.
Perhaps, we can clarify reborrowing like this : &'a *(&'b mut x).
It has borrowed x (which has a lifetime 'a in here),
but also borrowed a (which has a lifetime 'b).
So I ran the following code to confirm my conjecture.
let x: i32 = 1; // I wanted to make it clear that x lives in this scope.
let b;
{
let a = &mut x;
b = &mut *a;
}
*b = 0;
But this works!
What??
But I just decided to get this.
&'a mut *&mutx, not &'a mut *&'b mutx.
I had no idea why mut x is unavailable during the lifetime of &mut *&mutx nor why mut x is re-available after the lifetime of &mut *&mutx, but "okay, let's just say so".
But look at this. It's totally out of my mind for a clear and general understanding.
let x: i32 = 1;
let b;
{
let a = &mut x;
let b = &**&a;
} // error!! a should live longer than b!
Wasn't lifetime simply relying on what the real data b is referring to???
&'a **& &mut x, not &'a **&'b &'c mut x.
And now what??
&'a **&'b &mut x ??? (which was my guess).
How should I accept this complicated situation?
These are some great questions! I'll do my best to answer the ones I can.
The Rust Reference is a great place for finding answers to questions like this, about the deeper semantics of Rust.
First, for your question about method resolution, the Reference
says:
When looking up a method call, the receiver may be automatically
dereferenced or borrowed in order to call a method. This requires a
more complex lookup process than for other functions, since there may
be a number of possible methods to call. The following procedure is
used:
The first step is to build a list of candidate receiver types. Obtain
these by repeatedly dereferencing the receiver
expression's type, adding each type encountered to the list, then
finally attempting an unsized coercion at the end, and adding the
result type if that is successful. Then, for each candidate T, add
&T and &mut T to the list immediately after T.
For instance, if the receiver has type Box<[i32;2]>, then the
candidate types will be Box<[i32;2]>, &Box<[i32;2]>, &mut Box<[i32;2]>, [i32; 2] (by dereferencing), &[i32; 2], &mut [i32; 2], [i32] (by unsized coercion), &[i32], and finally &mut [i32].
The link above goes into more detail.
For the rest of your questions, I think this is mostly about type coercion. Some relevant coercions are:
&mut T to &T
&T or &mut T to &U if T implements Deref<Target = U>
&mut T to &mut U if T implements DerefMut<Target = U>
Notably, &U and &mut U both implement Deref<Target = U>, and &mut U also implements DerefMut<Target = U>. Therefore, the second/third rules lead to the following coercions:
Let T be:
Coerce from
To
&U
&&U
&U
&U
&mut &U
&U
&mut U
&&mut U
&U
&mut U
&mut &mut U
&mut U
Now with the reference out of the way, let's look at your questions in more detail:
let a = &mut x;
let b = &mut *a; // a isn't available from now on
*a = blahblah; // error! no more access allowed for a
*b = blahblah; // I've wrote this code not to confuse you of the lifetime of b. If not mentioned, it always live till the scope ends.
In order to write into a reference, it clearly must be a mutable (aka unique) reference. When you write let a = &mut x, now a is the only way to access x. Now when you write let b = &mut *a, it essentially means let b = &mut *(&mut x), which simplifies to let b = &mut x.
Here, b mutably borrows a, Rust will not let you use a until b is destroyed... or so it seems for now.
let a = &mut x;
{
let b = &*a;
// *a = blahblah in this scope will throw an error, just like above case.
}
*a = blahblah; // but this works.
Here, let b = &*a turns into let b = &*(&mut x), so let b = &x. No matter what kind of reference b is, a is a mutable reference and must be unique, so you can't use it until b is gone (out of scope).
let mut x: i32 = 1; // I wanted to make it clear that x lives in this scope.
let b;
{
let a = &mut x;
b = &mut *a;
}
*b = 0;
(I assume you meant let mut x).
Now this is where it gets interesting. Here, since a and b both mutably point to the same object, Rust will not let you use a until b is destroyed. It seems like the reasoning should be, "since b mutably borrows a", but that's actually not the case. Normally, b would in fact borrow a, and this is the case for smart pointers like Box, std::cell::RefMut, etc. However, references get special treatment: Rust can analyze the memory they point to.
So when you write let b = &mut *a, b doesn't actually borrow a! It only borrows the data a points to. This distinction wasn't relevant before, but here it is what allows the code to compile.
As for your last example, I can't get it to break in the way you described.

What's the semantic of assignment in Rust?

How could know the type of a binding if I use auto type deduction when creating a binding? what if the expression on the right side is a borrow(like let x = &5;), will it be value or a borrow? What will happen if I re-assign a borrow or a value?
Just for check, I do can re-assign a borrow if I use let mut x: &mut T = &mut T{}; or let mut x:&T = & T{};, right?
I sense some confusion between binding and assigning:
Binding introduces a new variable, and associates it to a value,
Assigning overwrites a value with another.
This can be illustrated in two simple lines:
let mut x = 5; // Binding
x = 10; // Assigning
A binding may appear in multiple places in Rust:
let statements,
if let/while let conditions,
cases in a match expression,
and even in a for expression, on the left side of in.
Whenever there is a binding, Rust's grammar also allows pattern matching:
in the case of let statements and for expressions, the patterns must be irrefutable,
in the case of if let, while let and match cases, the patterns may fail to match.
Pattern matching means that the type of the variable introduced by the binding differs based on how the binding is made:
let x = &5; // x: &i32
let &y = &5; // y: i32
Assigning always requires using =, the assignment operator.
When assigning, the former value is overwritten, and drop is called on it if it implements Drop.
let mut x = 5;
x = 6;
// Now x == 6, drop was not called because it's a i32.
let mut s = String::from("Hello, World!");
s = String::from("Hello, 神秘德里克!");
// Now s == "Hello, 神秘德里克!", drop was called because it's a String.
The value that is overwritten may be as simple as an integer or float, a more involved struct or enum, or a reference.
let mut r = &5;
r = &6;
// Now r points to 6, drop was not called as it's a reference.
Overwriting a reference does not overwrite the value pointed to by the reference, but the reference itself. The original value still lives on, and will be dropped when it's ready.
To overwrite the pointed to value, one needs to use *, the dereference operator:
let mut x = 5;
let r = &mut x;
*r = 6;
// r still points to x, and now x = 6.
If the type of the dereferenced value requires it, drop will be called:
let mut s = String::from("Hello, World!");
let r = &mut s;
*r = String::from("Hello, 神秘德里克!");
// r still points to s, and now s = "Hello, 神秘德里克!".
I invite you to use to playground to and toy around, you can start from here:
fn main() {
let mut s = String::from("Hello, World!");
{
let r = &mut s;
*r = String::from("Hello, 神秘德里克!");
}
println!("{}", s);
}
Hopefully, things should be a little clearer now, so let's check your samples.
let x = &5;
x is a reference to i32 (&i32). What happens is that the compiler will introduce a temporary in which 5 is stored, and then borrow this temporary.
let mut x: &mut T = T{};
Is impossible. The type of T{} is T not &mut T, so this fails to compile. You could change it to let mut x: &mut T = &mut T{};.
And your last example is similar.

Resources