# Interior mutability

> Mutate through a shared reference with Cell, RefCell, Mutex or atomics — the aliasing rule still holds, but it's checked at runtime.

Concept · Rust · https://levelcode.org/concepts/interior-mutability

[The borrow checker](https://levelcode.org/concepts/borrow-checker) allows mutation only through a unique `&mut T`. Some designs need shared owners who also mutate: a cache read by many parts of a program, a counter bumped from several places, a graph whose nodes point at each other. **Interior mutability** types allow mutation through a shared `&T` by enforcing the "one writer" rule some other way.

| Type | How it stays safe | Threads |
| --- | --- | --- |
| `Cell<T>` | Never hands out references: `get` copies, `set` replaces | One |
| `RefCell<T>` | Counts borrows at runtime; **panics** on a conflict | One |
| `Mutex<T>` | One locker at a time; others **block** | Many |
| `RwLock<T>` | Many readers or one writer; others block | Many |
| `AtomicU64`, `AtomicBool`… | Hardware atomic instructions | Many |

```rust
use std::cell::RefCell;

let log = RefCell::new(Vec::new());
log.borrow_mut().push("started");   // runtime-checked &mut
println!("{:?}", log.borrow());      // runtime-checked &
```

They're usually combined with shared ownership: `Rc<RefCell<T>>` on one thread, `Arc<Mutex<T>>` or `Arc<RwLock<T>>` across threads. Which ones may cross threads is decided by [Send and Sync](https://levelcode.org/concepts/send-and-sync).

## Costs and cautions

- The check moves from compile time to runtime: a conflicting `RefCell` borrow is a panic, a conflicting lock is a wait (or a deadlock).
- Keep borrows and lock guards short — borrow, use, drop — and never hold a `std::sync::Mutex` guard across an `.await`.
- `RefCell` everywhere is a design smell. Often one owner holding the data, with others sending it messages, is simpler.

See the [smart pointers lesson](https://levelcode.org/roadmaps/rust/smart-pointers) for when to use each.
