19

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?

1
  • Rust doesn't have anything similar to Java's final, since it doesn't support inheritance and variables are immutable by default. Java doesn't have anything similar to Rust's const, since Java tends to rely on the JVM to optimize things rather than doing compile time evaluation. Rust's const is more like C++'s constexpr and Java's final is more like C++'s const. Clear as mud! Commented May 31, 2018 at 21:17

2 Answers 2

22

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:

Sign up to request clarification or add additional context in comments.

Comments

3

For those who, like me, got here via Google because they got an error trying to use static mut with an AtomicUsize or AtomicBool:

static is what you want. static allows interior mutability, and that's what AtomicUsize and friends provide. The mut adds exterior mutability, which you probably don't want and is causing the error. You probably chose AtomicX because you wanted only the interior mutability, so remove the mut.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.