Similar to `Cell`, this is mainly useful for situations where it's hard or impossible to satisfy the
borrow checker. Generally we know that such mutations won't happen in a nested form, but it's good
to check.
For large, complicated programs, it becomes useful to put some things in `RefCell`s to make things
simpler. For example, a lot of the maps in [the `ctxt` struct][ctxt] in the rust compiler internals
are inside this wrapper. These are only modified once (during creation, which is not right after
initialization) or a couple of times in well-separated places. However, since this struct is
pervasively used everywhere, juggling mutable and immutable pointers would be hard (perhaps
impossible) and probably form a soup of `&`-ptrs which would be hard to extend. On the other hand,
the `RefCell` provides a cheap (not zero-cost) way of safely accessing these. In the future, if
someone adds some code that attempts to modify the cell when it's already borrowed, it will cause a
(usually deterministic) panic which can be traced back to the offending borrow.
Similarly, in Servo's DOM there is a lot of mutation, most of which is local to a DOM type, but some
of which crisscrosses the DOM and modifies various things. Using `RefCell` and `Cell` to guard all
mutation lets us avoid worrying about mutability everywhere, and it simultaneously highlights the
places where mutation is _actually_ happening.
Note that `RefCell` should be avoided if a mostly simple solution is possible with `&` pointers.
#### Guarantees
`RefCell` relaxes the _static_ restrictions preventing aliased mutation, and replaces them with
_dynamic_ ones. As such the guarantees have not changed.
#### Cost
`RefCell` does not allocate, but it contains an additional "borrow state"
indicator (one word in size) along with the data.
At runtime each borrow causes a modification/check of the refcount.
[cell-mod]: ../std/cell/
[cell]: ../std/cell/struct.Cell.html
[refcell]: ../std/cell/struct.RefCell.html
[ctxt]: ../rustc/middle/ty/struct.ctxt.html
# Synchronous types
Many of the types above cannot be used in a threadsafe manner. Particularly, `Rc<T>` and
`RefCell<T>`, which both use non-atomic reference counts (_atomic_ reference counts are those which
can be incremented from multiple threads without causing a data race), cannot be used this way. This
makes them cheaper to use, but we need thread safe versions of these too. They exist, in the form of
`Arc<T>` and `Mutex<T>`/`RWLock<T>`
Note that the non-threadsafe types _cannot_ be sent between threads, and this is checked at compile
time.
There are many useful wrappers for concurrent programming in the [sync][sync] module, but only the
major ones will be covered below.
[sync]: ../std/sync/index.html
## `Arc<T>`
[`Arc<T>`][arc] is just a version of `Rc<T>` that uses an atomic reference count (hence, "Arc").
This can be sent freely between threads.
C++'s `shared_ptr` is similar to `Arc`, however in the case of C++ the inner data is always mutable.
For semantics similar to that from C++, we should use `Arc<Mutex<T>>`, `Arc<RwLock<T>>`, or
`Arc<UnsafeCell<T>>`[^4] (`UnsafeCell<T>` is a cell type that can be used to hold any data and has
no runtime cost, but accessing it requires `unsafe` blocks). The last one should only be used if we
are certain that the usage won't cause any memory unsafety. Remember that writing to a struct is not
an atomic operation, and many functions like `vec.push()` can reallocate internally and cause unsafe
behavior, so even monotonicity may not be enough to justify `UnsafeCell`.
[^4]: `Arc<UnsafeCell<T>>` actually won't compile since `UnsafeCell<T>` isn't `Send` or `Sync`, but we can wrap it in a type and implement `Send`/`Sync` for it manually to get `Arc<Wrapper<T>>` where `Wrapper` is `struct Wrapper<T>(UnsafeCell<T>)`.
#### Guarantees
Like `Rc`, this provides the (thread safe) guarantee that the destructor for the internal data will
be run when the last `Arc` goes out of scope (barring any cycles).
#### Cost
This has the added cost of using atomics for changing the refcount (which will happen whenever it is
cloned or goes out of scope). When sharing data from an `Arc` in a single thread, it is preferable
to share `&` pointers whenever possible.
[arc]: ../std/sync/struct.Arc.html
## `Mutex<T>` and `RwLock<T>`
[`Mutex<T>`][mutex] and [`RwLock<T>`][rwlock] provide mutual-exclusion via RAII guards (guards are
objects which maintain some state, like a lock, until their destructor is called). For both of
these, the mutex is opaque until we call `lock()` on it, at which point the thread will block
until a lock can be acquired, and then a guard will be returned. This guard can be used to access
the inner data (mutably), and the lock will be released when the guard goes out of scope.
```rust,ignore
{
let guard = mutex.lock();
// guard dereferences mutably to the inner type
*guard += 1;
} // lock released when destructor runs
```
`RwLock` has the added benefit of being efficient for multiple reads. It is always safe to have
multiple readers to shared data as long as there are no writers; and `RwLock` lets readers acquire a
"read lock". Such locks can be acquired concurrently and are kept track of via a reference count.
Writers must obtain a "write lock" which can only be obtained when all readers have gone out of
scope.
#### Guarantees
Both of these provide safe shared mutability across threads, however they are prone to deadlocks.
Some level of additional protocol safety can be obtained via the type system.
A common gripe when reading Rust code is with types like `Rc<RefCell<Vec<T>>>` (or even more more
complicated compositions of such types). It's not always clear what the composition does, or why the
author chose one like this (and when one should be using such a composition in one's own code)
Usually, it's a case of composing together the guarantees that you need, without paying for stuff
that is unnecessary.
For example, `Rc<RefCell<T>>` is one such composition. `Rc<T>` itself can't be dereferenced mutably;
because `Rc<T>` provides sharing and shared mutability can lead to unsafe behavior, so we put
`RefCell<T>` inside to get dynamically verified shared mutability. Now we have shared mutable data,
but it's shared in a way that there can only be one mutator (and no readers) or multiple readers.
Now, we can take this a step further, and have `Rc<RefCell<Vec<T>>>` or `Rc<Vec<RefCell<T>>>`. These
are both shareable, mutable vectors, but they're not the same.
With the former, the `RefCell<T>` is wrapping the `Vec<T>`, so the `Vec<T>` in its entirety is
mutable. At the same time, there can only be one mutable borrow of the whole `Vec` at a given time.
This means that your code cannot simultaneously work on different elements of the vector from
different `Rc` handles. However, we are able to push and pop from the `Vec<T>` at will. This is
similar to an `&mut Vec<T>` with the borrow checking done at runtime.
With the latter, the borrowing is of individual elements, but the overall vector is immutable. Thus,
we can independently borrow separate elements, but we cannot push or pop from the vector. This is
similar to an `&mut [T]`[^3], but, again, the borrow checking is at runtime.
In concurrent programs, we have a similar situation with `Arc<Mutex<T>>`, which provides shared
mutability and ownership.
When reading code that uses these, go in step by step and look at the guarantees/costs provided.
When choosing a composed type, we must do the reverse; figure out which guarantees we want, and at
which point of the composition we need them. For example, if there is a choice between
`Vec<RefCell<T>>` and `RefCell<Vec<T>>`, we should figure out the tradeoffs as done above and pick
one.
[^3]: `&[T]` and `&mut [T]` are _slices_; they consist of a pointer and a length and can refer to a portion of a vector or array. `&mut [T]` can have its elements mutated, however its length cannot be touched.