4 ms·
Not staticassertion, but I'm a hobbyist in real-time audio. I like Rust as a vocabulary for describing/teaching safe programming (&/&mut/Send/Sync). I find that
by nyanpasu64 5y ago
Not staticassertion, but I'm a hobbyist in real-time audio. I like Rust as a vocabulary for describing/teaching safe programming (&/&mut/Send/Sync). I find that multithreaded programs written in Rust are usually correct while multithreaded programs written in C++ are usually wrong, because Rust encodes the rules of shared-memory threading in its type system (&T: Sync objects are thread-shared, but are either immutable or atomic or requires locking to acquire a &mut T). I also appreciate guiding users towards exclusive references (&mut) to make it easier to reason about code. However I find it makes it too difficult to mutate through shared references or write unsafe code (passing Stacked Borrows while lending out &mut is more like solving puzzles than writing imperative code, and writing code that never touches & and &mut is a quagmire of addr_of_mut!() and unsafe blocks on every pointer dereference), and the Rust community appears uninterested in making unsafe programming more ergonomic.
Personally I'm a fan of C++'s unique_ptr/& as an unsafe escape hatch from Rust's single ownership or runtime refcounting overhead. It's at least as safe as Rust's unsafe pointers, and far more pleasant to use. Qt's QObject ownership system is reasonably ergonomic and QPointer is fun (though dangerous since it can turn into null unexpectedly), but Qt uses it pervasively (rather than only when safe memory management fails), relies on prose documentation to describe which pointers transfer ownership or not (resulting in memory management bugs), and QObject child destruction and nulling-out QPointers relies on runtime overhead. I haven't tried ECS or generational indexes yet, but those are popular in games, and Vale has its own ideas in this field (https://verdagon.dev/blog/generational-references https://verdagon.dev/blog/generational-references).
On an aesthetic/principled level, I'd rather punt alias analysis to the programmer (pointer/restrict or &/&mut) rather than compiler complexity/magic (TBAA and provenance checking). Glancing at https://harelang.org/specification/ https://harelang.org/specification/, it seems Hare lacks an equivalent of restrict/&mut, and I wonder if that prevents the compiler from ever adding support for removing redundant loads/stores through pointers.
- zozbot234 5y ago> However I find it makes it too difficult to mutate through shared references It's not that difficult, you just need to use UnsafeCell<…> or one of its safe derivatives (each of which has some potential runtime overhead) to keep the semantics tractable.
- nyanpasu64 5y agoOne of the strange things about Rust is the &UnsafeCell<T>/*mut T dichotomy. &UnsafeCell<T> is easier to work with, and you can soundly acquire &mut T as long as they never overlap, but you can't turn a Box<UnsafeCell<T>> into a &UnsafeCell<T> and back to a Box<UnsafeCell<T>> to delete it, because provenance or something. *mut T is harder to work with, this is UB according to miri since you didn't specify `&mut x as *mut i32 as *const i32`: let mut x = 1; let px = &mut x as *const i32; unsafe { *(px as *mut i32) = 2; } Problem is, most APIs won't give you a &UnsafeCell<T> but rather a &mut T. Not sure if you can convert a &mut T to a &UnsafeCell<T> (you definitely can't using `as`). If you want to create multiple aliasing pointers into a non-UnsafeCell type or struct field, one approach (basically a placeholder since &raw isn't stable, https://gankra.github.io/blah/fix-rust-pointers/#offsets-and-places-are-a-mess https://gankra.github.io/blah/fix-rust-pointers/#offsets-and...) is: let mut x = 1; let px = addr_of_mut!(x); unsafe { *px = 2; }
- kzrdude 5y agoCell::from_mut converts from `&mut T` to `&Cell<T>` and that's a newtype around UnsafeCell - it has the same `as_ptr` method.
- zozbot234 5y agoThese are different things. UnsafeCell<T> is for shared mutable data. *mut T is for data that you assert will never be mutated while it's being shared with some other reference, but you can't rely on the compiler to prove this fact for you.
- nyanpasu64 5y agoIf I have a &mut T, what pointer type do I convert it into (and create multiple copies of), to allow shared mutation scoped within the lifetime of the source &mut T?
- zozbot234 5y ago
- vladharbuz 5y agoThank you for the resources, I'll look into these details in more depth!
- astrange 5y ago> On an aesthetic/principled level, I'd rather punt alias analysis to the programmer (pointer/restrict or &/&mut) rather than compiler complexity/magic (TBAA and provenance checking). That would certainly be nice, but the state of the art on what problems even are is far ahead in optimizing compilers than anyone else - "having a restrict keyword" doesn't solve every aliasing problem afaik, and nobody respects the performance people when they tell you undefined behavior in C is actually useful. So nobody has come up with a simple solution for a better language that solves problems like pointer provenance and yet is "faster than C". Actually most people's ideas of how to make programs faster are complicated things like autovectorization that don't work and would make it slower.