Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are const atomic variables not updated, but static atomic variables are?

Tags:

rust

I have this code:

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

const SOME_VAR: AtomicUsize = AtomicUsize::new(0);

fn main() {
    println!("{}", SOME_VAR.load(Ordering::SeqCst));
    println!("{}", SOME_VAR.fetch_add(10, Ordering::SeqCst));
    println!("{}", SOME_VAR.load(Ordering::SeqCst));
}

This prints 0 0 0 without any errors. In Java, I can use a final HashMap and add (k, v) to it. In Rust, I am surprised that the compiler is not yelling at me but also does not increment my atomic value. Am I doing something wrong here?

If I use a static:

static SOME_VAR: AtomicUsize = AtomicUsize::new(0);

I get the result 0 0 10. Why does it not work with const?

like image 216
misnomer___ Avatar asked May 31 '18 19:05

misnomer___


1 Answers

A static variable is guaranteed to have a single instance and you can take a reference to it. A const variable does not have this guarantee and the compiler is allowed to have zero, one, or multiple instances of it.

In your case, the code is equivalent to:

println!("{}", AtomicUsize::new(0).load(Ordering::SeqCst));
println!("{}", AtomicUsize::new(0).fetch_add(10, Ordering::SeqCst));
println!("{}", AtomicUsize::new(0).load(Ordering::SeqCst));

Since each value is created and thrown away, no changes from one propagate to the other.

In some ways, you can think of a const variable like a C or C++ #define — conceptually the value is just pasted wherever it's used.

Clippy 0.0.211 has a lint for this case:

error: a const item should never be interior mutable
 --> src/main.rs:3:1
  |
3 | const SOME_VAR: AtomicUsize = AtomicUsize::new(0);
  | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  | |
  | help: make this a static item: `static`
  |
  = note: #[deny(declare_interior_mutable_const)] on by default
  = help: for further information visit https://rust-lang-nursery.github.io/rust-clippy/v0.0.211/index.html#declare_interior_mutable_const

error: a const item with interior mutability should not be borrowed
 --> src/main.rs:6:20
  |
6 |     println!("{}", SOME_VAR.load(Ordering::SeqCst));
  |                    ^^^^^^^^
  |
  = note: #[deny(borrow_interior_mutable_const)] on by default
  = help: assign this const to a local or static variable, and use the variable here
  = help: for further information visit https://rust-lang-nursery.github.io/rust-clippy/v0.0.211/index.html#borrow_interior_mutable_const

In Java, I can use a final HashMap

Yes, you can make a non-thread-safe HashMap very easily in Java. Rust doesn't want to make it easy to create code that can lead to memory unsafety. You need to protect the type with appropriate safety, such as by a Mutex, or you need to dip into unsafe code if you the programmer guarantee that a global value will only ever be used by one thread.

See also:

  • Why do changes to a const variable not persist between usages?
  • How do I create a global, mutable singleton?
  • How can you make a safe static singleton in Rust?
like image 134
Shepmaster Avatar answered Nov 20 '22 19:11

Shepmaster