Conversation

So for example, if you have a nice recursive tree data structure, you can represent that with the nodes as Box<T>, which is a uniquely owned dynamic allocation. If you want to have cycles back from the children to the parent nodes, you need Rc<T> with Weak<T> for parent pointers.
1
So when you are actually using the parent pointer, you call upgrade(), which gives you an Option<Rc<T>> (since it might have been deallocated). You can do it, but you're encouraged to do things in a more simple way by the requirement for safety, like avoiding reference cycles.
2
Well it's worth noting these are all library features and in a kernel you are only using libcore rather than libstd which builds on it. You'd want to smart pointers and collections returning Option from methods making them for handling out-of-memory without needing unwinding.
2
Low-level library design for a low-level memory safe language is a very active ongoing research project. The ease of use and capabilities are advancing very quickly. I did a lot of work on it a few years ago including implementing iterator objects and a lot of collections, etc.
2
1
Shared ownership / mutability is inherently complicated. It's very difficult to verify as correct, whether you're a compiler or a human. It ventures outside of what Rust can statically verify as correct without runtime overhead like references, Box<T>, Vec<T>, iterators, etc.
1
2
Usually, the rules are all statically checked, such as the lifetime and aliasing rules for references, which compile down to raw pointers without instrumentation. If you want mutability in Rc<T>, that has to be dynamically checked, which is what Rc<RefCell<T>> provides.
1
So instead of &x, you get a reference with cell.borrow(), and a separate method for mutable references. It provides dynamic checking for the rule of preventing aliasing mutable references. If you avoid shared ownership, you avoid needing more verbose code and runtime checks.
2
1
Mutex<T> is basically the same thing, but the methods obtains the lock for you, and release it when the returned object goes out of scope. The standard lifetime checks prevent using reference derived from it after the RefCell/Mutex wrapper it gives you goes out of scope.
1
Mutex<T> is ever so slightly more painful to use than RefCell<T> for the single-threaded case, because if a thread panics it poisons the mutexes as it unwinds (to avoid inconsistent state). So instead of borrow() you do get().unwrap() which propagates the failure across threads.
1
So what returning Option<T> there does propagate the failure if a thread actually panics while holding the mutex lock, since it might have left whatever it's protecting in an inconsistent state. If you just abort on panic, you don't need that part of the API design.
1
Show replies