#Why can't you mutably borrow a variable twice?

38 messages · Page 1 of 1 (latest)

vagrant flare
#

I keep getting errors about this and im confused why this error even exists.

#

Why can't you mutably borrow a variable twice?

charred goblet
#

Only one &mut T can exist per value at a time

vagrant flare
#

the documentation mentions "data races" and mentions how thats bad, but im confused on how that can create undefined behavior without multithreading

charred goblet
vagrant flare
#

oh

#

nvm

#

why?

charred goblet
#

The optimizer actually does optimizations based on it

charred goblet
#

So it doesn't have to keep reading the value on each use

vagrant flare
#

is that correct?

charred goblet
vagrant flare
charred goblet
#

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

iron raftBOT
#
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
charred goblet
#

This always calls print

#

The C version has to check that b didn't change

vagrant flare
#

Ohhhhhhhhh

#

fair enough

charred goblet
#

This is just one example of an optimization the knowledge of &mut T only having one allows

inland tundra
#

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");
    }
}
iron raftBOT
#
example::foo:
        mov     dword ptr [rdi], 100
        ret
```Note: only public functions (`pub fn`) are shown
charred goblet
#

Yeah, I should have done it that way

quaint wave
#

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?

charred goblet
#

Ah that's a good example

mystic stratus
#

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