#Why can't you mutably borrow a variable twice?
38 messages · Page 1 of 1 (latest)
Only one &mut T can exist per value at a time
https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html#mutable-references for some discussion of this
the documentation mentions "data races" and mentions how thats bad, but im confused on how that can create undefined behavior without multithreading
The thing is the existence is classified as UB all by itself
UB?
oh
nvm
why?
The optimizer actually does optimizations based on it
wdym
The optimizer knows a &mut T can never have it's value change out from under it
So it doesn't have to keep reading the value on each use
No? what would be the difference between 2 mutable references to the same value? they are the same and can be treated as such
is that correct?
You could change the value through the other one
whats the difference between *mutref1 = value vs *mutref2= value?
For example
let mut x = 42;
foo(&mut x, &mut x);
fn foo(a: &mut i32, b: &mut i32) {
let c = *b;
*a = 100;
if *b == c {
println!("hi");
}
}
Rust knows that hi will always happen
C code would not
?godbolt ```rs
pub fn foo(a: &mut i32, b: &mut i32) {
let c = *b;
*a = 100;
if *b == c {
println!("hi");
}
}
example::foo:
sub rsp, 56
mov dword ptr [rdi], 100
lea rax, [rip + .L__unnamed_1]
mov qword ptr [rsp + 8], rax
mov qword ptr [rsp + 16], 1
lea rax, [rip + .L__unnamed_2]
mov qword ptr [rsp + 24], rax
xorps xmm0, xmm0
movups xmmword ptr [rsp + 32], xmm0
lea rdi, [rsp + 8]
call qword ptr [rip + std::io::stdio::_print@GOTPCREL]
add rsp, 56
ret
.L__unnamed_3:
.ascii "hi\n"
.L__unnamed_1:
.quad .L__unnamed_3
.asciz "\003\000\000\000\000\000\000"
.L__unnamed_2:
```Note: only public functions (`pub fn`) are shown
This is just one example of an optimization the knowledge of &mut T only having one allows
Looks even better if you reverse it
?godbolt
pub fn foo(a: &mut i32, b: &mut i32) {
let c = *b;
*a = 100;
if *b != c {
println!("hi");
}
}
example::foo:
mov dword ptr [rdi], 100
ret
```Note: only public functions (`pub fn`) are shown
Yeah, I should have done it that way
not without restrict ;)
also the more important point is enums: ```rs
let mut a = Some(1);
let inside = &mut a.as_mut().unwrap();
a = None; // assignment requires mutability
dbg!(inside); // what's over here?
Ah that's a good example
There's also the classic example of borrowing a Vec element, then extending the Vec:
let mut vect = vec![3, 5];
let foo = &vect[0];
vect.extend([8, 13, 21]);
println!("{foo}"); // would be UB if it was allowed
?miri
let mut vect = vec![3, 5];
let foo: *const _ = &vect[0];
vect.extend([8, 13, 21]);
println!("{}", unsafe { *foo });