Rust &f32 vs C &const float


This is related to Is there a way to implement Index/IndexMut on a Vec<Cell<f32>>

Is the following correct: Rust’s &f32 offers far far greater guarantees than C’s &const float.

  1. A &const float in C/C++ says: I can not change this variable via this ref, however some other piece of code can change it at will.

  2. A rust &f32, due to borrow rules, says: during the lifetime which I hold this ref, NO ONE (outside of unsafe) is allowed to modify the underlying f32.

Is this correct?



C doesn’t have references, only C++, but I suspect the answer will be similar to const* anyway. I don’t recall whether writes are allowed from elsewhere though.

If unsafe code forces a write, this is UB, which you might as well call “not allowed” too. Most likely this just means that the readers might not see that update, but all bets are off.



This is correct. Rust’s shared references have a strong guarantee that the data is immutable (and exclusive references that the data is not seen by anyone else at the same time)

1 Like


Oh, I should add that the immutability is logical, not physical in memory. Cell, RefCell, Mutex, etc. can mutate data behind a shared reference, but they force the code to do it with synchronization or atomic access.



And those all mutate through UnsafeCell, which is a lang item getting special treatment in the compiler.



For even more clarification: that only applies to references to types that actually contain UnsafeCell, such as &Cell<f32>. &f32 itself is truly immutable as long as it exists; there is no (legal) way to somehow use UnsafeCell to mutate it.

1 Like


Could you please clarify this a bit? Of course, I didn’t dive deep into the code, but AFAIK, the definition of UnsafeCell is simply “hold the value, give the * mut to it on demand” (and other Cell types are safe wrappers around this pointer). Is there anything else underneath?



UnsafeCell gets special treatment by the compiler in being allowed to mutate its internals via a shared reference. Values that don’t involve an UnsafeCell can be assumed to never change through a shared reference under any circumstances.

1 Like


Its #[lang = "unsafe_cell"] attribute is what indicates special treatment. You can search for that in the compiler sources to track down its effect in more detail. This blog post also offered a good overview of lang items: