4 ms·
I jump in and find a section about borrow checker. At the end, this book explicitly recommends using smart pointer (RC and RefCell) to write your internal DS to
by mrbonner 3y ago
I jump in and find a section about borrow checker. At the end, this book explicitly recommends using smart pointer (RC and RefCell) to write your internal DS to pass them around instead of convoluted one and fight with the borrow checker.
I never have seriously coded in Rust but this is what observed as well. I mean how much of an overhead if RC comparing to the real borrow checker coming from Java or JS world? What are your pro Rust dev opinions about the use of RC in the real world?
- MuffinFlavored 3y ago> (RC and RefCell) Rc is Reference Counting Arc is Atomic Reference Counting RefCell is Reference Cell I'm like a "medium at Rust" person and I very rarely use Box or RefCell or Rc. I wonder what I'm missing due to not really understanding them/when to use them. I don't really use lifetimes either. Maybe I'm not that "medium"...
- cmrdporcupine 3y agoMy personal opinion on these is, it's probably good you're not using them all over: use only when needed, and be clear if you really need them. Basically: Box is used rather frequently, it basically corresponds to unique_ptr in C++, and is basically a way of a) having something be a passable heap-allocated thing and b) is often used to hold dyn implementations of a trait. Excessive instances of Box<dyn .. in your code are often a sign or code smell that you're bringing patterns from object-oriented languages through polymorphism via traits into what's really a non-OO language. See also: the Effective Rust entry about preferring generics over traits. Note at one point Box actually had its own special syntax (sigil ~) this was dropped. I am not a Rust core expert, but to me this feels like maybe a mistake...? Rc is sort of the "out" for when the borrow checker is giving too many problems for a given access pattern and you want to share a piece of state more conveniently within one thread. It's not used very often, you'll see more uses of Arc. Arc is generally used for shared state across threads. It can be combined with Mutex to create safe shared mutable state. RefCell's use is basically pushing borrow checking into the runtime instead of at compilation. Its main use is for the so-called "interior mutability pattern": https://doc.rust-lang.org/book/ch15-05-interior-mutability.html https://doc.rust-lang.org/book/ch15-05-interior-mutability.h... -- basically allowing mutable borrow in an immutable context (e.g. immutable self reference). So really, you shouldn't be reaching for this often. This is more something that data structure library designers might use in a "trust me, I know what I'm doing" way, or for, say a use like incrementing a usage counter or something which you know isn't really mutating state and you want do it inside an immutable reference. Similar to some uses of const_cast in C++, I guess.
- MuffinFlavored 3y ago> use only when needed I don't know when to use them/I probably just go for Arc<Mutex<T>> instead when I probably shouldn't?
- cmrdporcupine 3y agoYou only need the Arc<Mutex if you have multiple threads touching something. And don't worry, the compiler will let you know you gone-messed-up before you get there by angrily telling you about your lack of Send and Sync all over. Honestly, if you are in a multithreaded world, you are going to make your life a lot easier by reducing your shared mutable state and instead using channels (crossbeam or mpsc) to communicate and coordinate. This will reduce your need to toss things in Arc<Mutex, and in fact reduce a lot of borrow checker issues generally.
- MuffinFlavored 3y agoSay I'm "single threaded" (more simple). When to use Rc/RefCell then?
- cmrdporcupine 3y agoAs I said above, roughly: Rc for if you have some piece of data shared between (non-concurrent) components, that is maybe hard to manage with borrowing? I personally would try to fix this rather than rely on Rc, but there are legit cases. RefCell for if you want to manage the borrowing at runtime instead of at compile. Basically it will raise a panic at runtime if more than one person borrows off it. And it allows you to borrow something mutably (borrow_mut()) even if the surrounding thing is immutable or there are other mutable references. People use this for the "interior mutability pattern"; Additional examples would be e.g.: I have an internal counter I want to increment every time you call this function, and that's mutable, but the surrounding ref to the struct is immutable and I want to keep it that way. I could keep the counter in a RefCell and then borrow it immutably into a RefMut even tho the context I'm doing it in is immutable. It's basically "unsafe" code, really, buyer beware. Apply carefully.
- duped 3y agoI write Rust professionally. If you're using Rc you probably mean Arc. And most of the time that you mean Arc you mean Box. If you're using RefCell you probably have a bad data model. The use case is interior mutability. This turns out to not be that useful in practice if you designed your DS well. Occasionally you need it in the design of some internals, but it's rare (and rare to expose) If you're fighting the borrow checker you're not writing idiomatic Rust. > I mean how much of an overhead if RC comparing to the real borrow checker coming from Java or JS world? Negligible, but the real question is "why do you need RC in the first place?"
- ramranch 3y agoThere are certainly areas where idiomatic Rust needs to fight against the borrow checker. If that wasn't the case, things like `ouroborous` and `pin_project` wouldn't be as widely used as they are.
- duped 3y agoDay to day rust users shouldn't care too much about pin_project since the big use case for pin is handrolled futures and executors. Most folks just use adaptors from the futures crate and one of a handful of executors in the ecosystem. I've never actually heard of that other crate. It looks like most of its downloads come from its direct/indirect dependents like glium. I'd say if you're writing self referential data structures you're not writing idiomatic Rust.
- tmpfs 3y agoGot to disagree here, a typical use case based on my experience is a parser holding a &str as well as an AST that does zero-copy references into the string.