BorrowMut trait modifies my code behavior

Hello,

I'm currently learning Rust with Rust in Action, and my autocomplete engine automatically added the first commented line in my program which causes it to say that accessing the members of a Rc<RfCell< GroundStation >> is illegal, but if I comment it out everything works fine. I'm interested in why and also how the error occurs:

// use std::borrow::BorrowMut;
use std::cell::RefCell;
use std::rc::Rc;

#[derive(Debug)]
struct GroundStation {
    radio_freq: f64, // Mhz
}

fn main() {
  let base: Rc<RefCell<GroundStation>> =
      Rc::new(RefCell::new(GroundStation { radio_freq: 87.65 }));

  println!("base: {:?}", base);

  {
    let mut base_2 = base.borrow_mut();
    base_2.radio_freq -= 12.34;
    println!("base_2: {:?}", base_2);
  }

    println!("base: {:?}", base);

    let mut base_3 = base.borrow_mut();
    base_3.radio_freq += 43.21;

    println!("base: {:?}", base);
    println!("base_3: {:?}", base_3);
}

The problem is that BorrowMut provides a method called .borrow_mut() that is unrelated to RefCell::borrow_mut(), and implemented for a lot of types. The compiler doesn't know which one you meant, and the method search algorithm tries borrowing the receiver to make &mut Rc<RefCell<GroundStation>> before it tries dereferencing the receiver to make &RefCell<GroundStation>, so it finds the blanket impl BorrowMut for T before it finds RefCell's method.

This is an unfortunate name collision, which we could wish had been avoided by giving RefCell or Borrow and BorrowMut different names, but we have to live with it. Just make sure never to accept a suggestion to import Borrow or BorrowMut unless you actually want to use those traits.

3 Likes

Thanks a lot for the explanation!

Those suggestions should probably just be dropped, at least if there's a RefCell anywhere in sight...

1 Like