Why this code doesn't panic?


#1

Hi. I tried to have shared mutable owners with only RefCell and withour Cell or RC.

use std::cell::RefCell;

fn main() {
    let x = RefCell::new(vec![1, 2, 3]);

    let z = &x;
    let y = &x;

    z.borrow_mut().push(1);
    y.borrow_mut().push(2);

    println!("{:?}", x.borrow());
}

This prints [1, 2, 3, 1, 2]. Am I not supposed to get a panic? What happens when you create a reference to RefCell?


#2

z.borrow_mut() this creates a temporary variable type RefMut giving exclusive access. At end of line the variable is dropped and other calls can freely gain access.

let mut b =  z.borrow_mut();
b.push(1);

when inserted gives panic on next access attempt.

More tricky;

let c = |_| { y.borrow_mut().push(2); };
c(z.borrow_mut().push(1));

Gives panic as arguments don’t drop temporaries until after the call.


#3

I’d really like to see papercuts like this removed from the language. Once someone experiences this and does some research to understand the cause, they can work around it by, eg, putting the argument into a block and turning it into a statement. But, stuff like this doesn’t belong in a language so generally hyper focused on correctness as Rust.

This is also another reason to avoid RefCell as much as possible, although unfortunately some scenarios pretty much require it today. And of course you can get yourself into a deadlock with similarly structured code that uses a Mutex instead of RefCell :frowning: