Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do Rust's `Atomic*` types use non-mutable functions to mutate the value?

Tags:

rust

I notice that Rust's Atomic* structs have functions which modify the value, such as fetch_add. For instance, I can write this program:

use std::sync::atomic::{AtomicUsize, Ordering};

struct Tester {
    counter: AtomicUsize
}

impl Tester {
    fn run(&self) {
        let counter = self.counter.fetch_add(1, Ordering::Relaxed);
        println!("Hi there, this has been run {} times", counter);
    }
}

fn main() {
    let t = Tester { counter: AtomicUsize::new(0) };
    t.run();
    t.run();
}

This compiles and runs fine, but if I change the AtomicUsize to a normal integer, it will (correctly) fail to compile due to mutability concerns:

struct Tester {
    counter: u64
}

impl Tester {
    fn run(&self) {
        self.counter = self.counter + 1;
        println!("Hi there, this has been run {} times", self.counter);
    }
}
like image 529
Ronald Smith Avatar asked Mar 05 '16 06:03

Ronald Smith


1 Answers

It wouldn’t be very useful if it didn’t work this way. With &mut references, only one can exist at a time, and no & references at that time, so the whole question of atomicity of operation would be moot.

Another way of looking at it is &mut are unique references, and & aliasable references. For normal types, mutation can only safely occur if you have a unique reference, but atomic types are all about mutation (via replacement) without needing a unique reference.

The naming of & and &mut has been a fraught matter, with much fear, uncertainty and doubt in the community and documents like Focusing on Ownership explaining how things actually are. The language has ended up staying with & and &mut, but &mut is actually about uniqueness rather than mutability (it’s just that most of the time the two are equivalent).

like image 114
Chris Morgan Avatar answered Oct 21 '22 03:10

Chris Morgan