I am reading the documentation on RefCell and Cell to better wrap my head around interior mutability and when to use it.
I came across this statement and I was wondering if anyone could help me unpack it a bit.
RefCell<T> uses Rust's lifetimes to implement 'dynamic borrowing', a process whereby one can claim temporary, exclusive, mutable access to the inner value. Borrows for RefCell<T> s are tracked 'at runtime', unlike Rust's native reference types which are entirely tracked statically, at compile time. Because RefCell<T> borrows are dynamic it is possible to attempt to borrow a value that is already mutably borrowed; when this happens it results in thread panic.
It seems to me that if this is only used in single threaded applications, what is the situation where a thread panic need to arise. In a single threaded application there should be no fear of data races, and no simultaneous borrows, so what is the situation that would cause a thread panic?
I can imagine it's more for debugging more complex programs. For example, (for whatever reason) suppose you have a single-threaded runtime that's being interacted-upon by a multithreaded runtime. With proper implementation, this could safely be done in Rust especially with mutexes on the interaction layer between the multithreaded -> single threaded boundary. However, if someone makes a communicator that allows sending two jobs to the single-threaded environment in concurrence, then the RefCell could panic. It's really there to help insantiate good programming practice. This is at least one way I can see that the panic could be useful for debugging, but I'm sure there are other ways
The panic is not to protect you from data races, rather it's to protect you from modifying things while you have a reference to them. Observe:
fn main() {
let cell = RefCell::new(vec![5]);
// Get a reference to the five
let ref1 = cell.borrow();
let ref_to_5 = &ref1[0];
// Clear the list.
let mut ref2 = cell.borrow_mut();
ref2.clear();
// Oops, the reference is invalidated.
println!("{}", ref_to_5);
}
The above will compile but panic. It compiles due to the fact that borrow_mut takes an immutable reference to the RefCell — if you wrote the example above without a RefCell, you would get a compile error due to needing a mutable reference to clear the vector (playground).