patternrustCritical
Need holistic explanation about Rust's cell and reference counted types
Viewed 0 times
aboutcountedandexplanationcelltypesrustholisticreferenceneed
Problem
There are several wrapper types in the Rust standard library:
As I understand it, these are wrappers which provide further possibilities than a simple reference. While I understand some basics, I cannot see the whole picture.
What do they do exactly? Do cells and reference-counted families provide orthogonal or similar features?
- The cells in the
std::cellmodule:CellandRefCell
- The reference-counted wrappers, like
RcandArc.
- The types in the
std::syncmodule:MutexorAtomicBoolfor example
As I understand it, these are wrappers which provide further possibilities than a simple reference. While I understand some basics, I cannot see the whole picture.
What do they do exactly? Do cells and reference-counted families provide orthogonal or similar features?
Solution
There are two essential concepts in Rust:
The various pointer types (
On the other hand, the various cells (
The founding rule of Rust's safety is Aliasing NAND Mutability. That is, an object can only be safely mutated if there is no outstanding reference to its interior.
This rule is generally enforced at compile time by the borrow checker:
However, sometimes, this is not flexible enough. Sometimes you DO need (or want) the ability to have multiple references to the same object and yet mutate it. Enter the cells.
The idea of
This functionality is sometimes described as providing interior mutability, that is where an object which otherwise looks immutable from the outside (
When this mutability extends across multiple threads, you will instead use
If you come from a C++ background:
And the cells provide a similar functionality as
- Ownership,
- Mutability.
The various pointer types (
Box, Rc, Arc) are concerned with Ownership: they allow controlling whether there is a single or multiple owners for a single object.On the other hand, the various cells (
Cell, RefCell, Mutex, RwLock, AtomicXXX) are concerned with Mutability.The founding rule of Rust's safety is Aliasing NAND Mutability. That is, an object can only be safely mutated if there is no outstanding reference to its interior.
This rule is generally enforced at compile time by the borrow checker:
- if you have a
&T, you cannot also have a&mut Tto the same object in scope,
- if you have a
&mut T, you cannot also have any reference to the same object in scope.
However, sometimes, this is not flexible enough. Sometimes you DO need (or want) the ability to have multiple references to the same object and yet mutate it. Enter the cells.
The idea of
Cell and RefCell is to permit mutability in the presence of aliasing in a controlled manner:Cellprevents the formation of reference to its interior, avoiding dangling references,
RefCellshifts the enforcement of Aliasing XOR Mutability from compile time to runtime.
This functionality is sometimes described as providing interior mutability, that is where an object which otherwise looks immutable from the outside (
&T) can actually be mutated.When this mutability extends across multiple threads, you will instead use
Mutex, RwLock or AtomicXXX; they provide the same functionality:AtomicXXXare justCell: no reference to the interior, just moving in/out,
RwLockis justRefCell: can obtain references to the interior through guards,
Mutexis a simplified version ofRwLockwhich does not distinguish between a read-only guard and write guard; so conceptually similar to aRefCellwith only aborrow_mutmethod.
If you come from a C++ background:
Boxisunique_ptr,
Arcisshared_ptr,
Rcis a non thread-safe version ofshared_ptr.
And the cells provide a similar functionality as
mutable, except with additional guarantees to avoid aliasing issues; think of Cell as std::atomic and RefCell as a non thread-safe version of std::shared_mutex (which throws instead of blocking if the lock is taken).Context
Stack Overflow Q#45674479, score: 195
Revisions (0)
No revisions yet.