Immutable references

Rust, as a language, offers two novel paradigms:

Now, you may ask why Rust was designed this way, and the answers can be pretty interesting, but it does not change the fact that Rust works this way. An exclusive reference, by design, must be exclusive.

To rephrase your question:

what is the point of exclusive references for simple types such as integers? More generally, how useful can it be to have a &mut reference on something that is Copy?

At that point, multi-threading is the answer: contrary to other languages, Rust opts into thread-safe paradigms by default (i.e., thread-safety is opt-out rather than opt-in). This raises two questions:

  • how is &mut needed for thread-safety / to avoid data-races?

    Well, you can use exclusive references to mutate data (that's why the are called "mutable references" in an overly simplifying manner, and why the carry mut in their rather than the more apt uniq...) in an unsynchronized manner (e.g., imagine doing *xr += 1; in your example).

    So now imagine doing let xr1 = mutable_ref_to(x); (pseudo-code), and let xr2 = mutable_ref_to(x);
    If that were possible, then you would be able to go and use xr1 in one thread to do *xr1 +=1 and xr2 in another thread and do *xr2 += 1. This would result in a data race, meaning that the value of x "afterwards" would be undefined.

  • how do I opt-out of thread safety? How do I get non-exclusive mutable references to simple types such as integers (or other Copy types)?

    The answer is to stop using exclusive references, and to instead wrap your type (e.g., and integer) in a Cell use a shared reference (& _) to that Cell:

    use std::cell::Cell;
    
    let x = Cell::new(10);
    let xr = &x; // "mutable but non-exclusive reference to `x`"
    println!("{}", x.get()); // 10
    xr.set(42); // mutate!
    println!("{}", x.get()); // 42
    
    • (For those wondering if &Cell contradicts what I said about the data race in my first point, know that it is not possible to Send a mutable reference of type &Cell to another thread because Cell is not Sync, i.e., precisely because Cell offers "shared mutation" (also called interior mutability) that is not Sync-hronized / thread-safe.
8 Likes