Hacker News new | past | comments | ask | show | jobs | submit login

> The typical Rust program has either no refcells, or a very small number, just as it has either no unsafe code or a very small amount

Really? How are we quantifying this?




I don't think anyone has actual measurements on this, but at the same time anyone who's written and read a significant amount of Rust[1] can tell you that unsafe and RefCell aren't something you encounter every day (or even every year when it comes to RefCell).

[1] for my part I've been doing it full time for the past 7 years, and also teach Rust at university.


What about Arc<Mutex<T>> ?


In six years I wrote a lot of the 200K lines of Rust for Pernosco --- a fairly sophisticated application server for a SaaS debugger. There are 40 instances of the string 'Arc::new(Mutex::new('. A lot of them are shared caches and other innocuous things. There are 22 occurrences of 'RefCell::new('. There are other uses of Arc, and other uses of Mutex, but fundamentally the system has not collapsed into an arbitrary graph of mutable data.

Of course, one's mileage can vary. Most of our system is designed to be stateless at the top level, which helps.


It's indeed more common than RefCell, but it's not like you're using them everywhere either (as using multiple locks is a recipe for deadlocks, so you should always be very mindful about how you use shared memory between threads).

I've run a quick analysis on the 1,145,666 lines of Rust code (excluding comments and blank lines) I have on my computer, which belong to several code bases I've worked on over the past few years (professional proprietary code, side projects and open source projects I just cloned to fiddle with), and here are the results:

- unsafe: 8247 matches, 1 every 138 lines (though keep in mind most of those aren't about mutable aliasing at all, like FFI or SIMD intrinsic)

- RefCell: 252 matches, 1 every 4546 lines

- Arc<Mutex<: 199 matches, 1 every 5757 lines

I think that's fair to say that “The typical Rust program has either no refcells, or a very small number, just as it has either no unsafe code or a very small amount”


Mutex<RefCell<T>> is a common pattern in embedded for setting up globals that are accessed from a critical section.


… sorry, I’m having my first coffee of the morning, so I’m probably missing something: what would putting a RefCell inside a mutex buy you? You’re already ensuring unique access with the Mutex, how would you ever get multiple accesses to the RefCell?


I'm not sure! The critical section-ed Mutex prevents the multiple accesses; Note that you generally have an Option inside the RefCell, so you can initialize it as a static, then assign to it later. Maybe that's related

For copy types, you can use `Cell` instead. And of course, atomics for primitive types.


Wouldn't you want the option outside? That's the usual pattern with "I want to assign later."

Anyway, I haven't seen this type used in the embedded projects I've worked on, do you have an example? Maybe I can suss out the reason from that.


I don't have examples, as the OSS code bases I can find either A: Don't have practical examples, or B: Use RTIC or Embassy.

Here's what happens if you leave out the RefCell:

  TEST.borrow(cs).replace(Test {});


  error[E0596]: cannot borrow data in a `&` reference as mutable
If you use Option on the outside, I'm not sure how to then set or access the variable:

  static TEST: Mutex<Option<RefCell<Test>>> = Mutex::new(None);
What would you recommend as an alternative? Use case: Sharing state between interrupt handlers and similar.


Ah! So this is an unfamiliarity issue on my part: I didn’t realize cortex_m::interrupt::Mutex has a different API than std::sync::Mutex or the various spinlock mutices. It deliberately only provides immutability because they want you to be able to choose how to do the interior mutability yourself. Now this all seems reasonable. Tricky!

(With hubris the interrupt stuff is abstracted away so you don’t need to access stuff this way, hence at least some of that unfamiliarity.)


I appreciate the insight! Forgot to mention it was that Mutex. Of note, the syntax is kind of messy (Especially the access syntax, which I omitted), but it's not so bad with macros.


Rust developers are loathe to use RefCells when a mutable borrow does the trick. It's preferable to rearchitect your solution than to use a RefCell. RefCells are a last resort, just as with unsafe.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: