5 ms·
I tried to get into rust for many years, I'm now in a C/CPP job (after Java/Python/Ruby and other gigs). What I've come to understand is that Rust's lifetime mo
by lumost 3y ago
I tried to get into rust for many years, I'm now in a C/CPP job (after Java/Python/Ruby and other gigs). What I've come to understand is that Rust's lifetime model is very difficult to work with whenever you have a cyclic reference. In C/CPP the same holds, but you deal with it through clever coding - or ignoring the problem and cleaning up memory later. Java, and other GC'd languages just work for these structures.
While the Rust devs believe such cyclic references are rare - I think this speaks mostly to the problem domain they are focused on. Relational models are everywhere in Apps, they are often common in complex systems software like databases, and they are fairly rare in firmware/drivers/system code code.
There are a few patterns for dealing with cyclic references, but they all end up requiring either unsafe or a main "owner" object which you clean up occassionally (effectively arena allocation). Having now worked in C/CPP - the idea of having unsafe blocks sprinkled around the code doesn't bother me, and many C/CPP components have some form of arena allocation built-in. I just wish Rust learning resources would be more upfront about this.
- goku12 3y ago> I just wish Rust learning resources would be more upfront about this. While beginner resources don't dwell too much upon cyclic references, they don't consider unsafe blocks as unusual. All the material I've seen say that there are certain domains where Rust's compile-time safety model simply won't work. What Rust allows you to do instead, is to limit the scope of unsafe blocks. However, the beginner material often won't give you too much details on how to analyze and decide on these compromises. Anyway, compile-time safety checks (using borrow checker) and manual safety checks (using unsafe) aren't the only way to deal with safety. Cyclic references can be dealt with runtime safety checks too - like Rc and Weak.
- mtsr 3y ago> Cyclic references can be dealt with runtime safety checks too - like Rc and Weak. Indeed. Starting out with code sprinkled with Rc, Weak, RefCell, etc is perfectly fine and performance will probably not be worse than in any other safe languages. And if you do this, Rust is pretty close to those languages in ease of use for what are otherwise complex topics in Rust. A good reference for different approaches is Learn Rust With Entirely Too Many Linked Lists https://rust-unofficial.github.io/too-many-lists/ https://rust-unofficial.github.io/too-many-lists/
- lumost 3y agoYou still need a main owner in those patterns, that owner must be part of a DAG of owners - you cannot have cyclic ownership.
- pncnmnp 3y agoAlso, take a look at GhostCell (https://plv.mpi-sws.org/rustbelt/ghostcell/ https://plv.mpi-sws.org/rustbelt/ghostcell/ and https://www.youtube.com/watch?v=jIbubw86p0M https://www.youtube.com/watch?v=jIbubw86p0M). If anyone's used this in a project or production environment, I'd love to hear your firsthand experiences and insights.
- pjmlp 3y agoExcept in those other languages the compiler types .clone() for me.
- chalsprhebaodu 3y agoSometimes the compiler types clone for you even you don’t actually want it to.
- pjmlp 3y agoIt is easier to tell it, "don't do it this time" than all the time. It is no accident that while Val/Hylo, Chapel and Swift have taken inspiration from Rust, they have decided to not inflict the affine types directly into the language users, rather let the compiler do part of the work itself.
- lifthrasiir 3y ago> Relational models are everywhere in Apps, they are often common in complex systems software like databases, and they are fairly rare in firmware/drivers/system code code. It's not like that you can't write relational models in the safe Rust. The only forbidden thing is a reference pointing arbitrary memory, which is typically worked around via indices and often more performant in that way. It is much rarer to find applications that need an absolutely random pointer that can't be hidden in abstractions in my opinion.
- mjevans 3y agoWhat's a frequently encountered case for such cyclic loops? Without details I'm drawn to trying to break the cycle, either by promoting the shared state to a container object for the set, or by breaking it out into it's own object that multiple things can point at.
- solomonb 3y agoASTs
- lifthrasiir 3y agoASTs are one of "nicely behaving" data structures. It is like a archetype of abstract data types pervasive in functional programming languages.
- mjevans 3y agoAn Abstract Syntax Tree / or Double-Linked List both qualify, but they're also a lower level implementation detail than I'd expect to frequently interact with in a reference safety focused language. I've still been meaning to write something in / learn Rust's ways of thinking; is there not an intended replacement for these data structures? Or do they expect it all to go under Unsafe?
- littlestymaar 3y ago> is there not an intended replacement for these data structures? Or do they expect it all to go under Unsafe? For linked-lists, there's one in std and the majority of people should never have to write their own as it's error prone and requires unsafe. For graph use-case then you can either use ECS, arena, ref counting or unsafe, but you're probably better off using/developing a dedicated crate that optimizes it and abstract it away behind an easy to use (and safe) interface.
- lumost 3y agoThe one in std uses unsafe. My main concern with learning rust is that you can spend ages trying to learn “the right way” of doing things in rust, when the right way really is to use unsafe.
- worik 3y ago> While the Rust devs believe such cyclic references are rare - They are. I have not had to use cyclic references ever, except once doing experiments with fully connected graphs, that was very unusual If you're doing a lot cyclic references Rust is not the right choice. Horses for courses But are you sure you're using the best algorithm?
- jcelerier 3y agoMaybe for you it's unusual - in my previous work all the apps contained graphs, and I just joined a company where almost all the apps also contain graphs
- underdeserver 3y agoI don't write Rust, but I never understood why graphs meant you need circular references. Doesn't it just come down to the question of who owns the node? If it's a tree, and parents are never removed before children, just make the child owned by the parent and keep a weak reference to the parent. If it's a general graph, and vertices can exist or not exist regardless of edges, keep a list of them independent of the edges, and keep weak references in the edges. If it's a graph where a one or a few roots exist, and nodes exist as long as there's a path from a root node to them, that sounds like a classic use case for Rc<>. Is there a common use case I'm missing?
- lumost 3y agoThings get tricky when you have a valid triangular relationship amongst equal objects. This comes up far more often than you’d expect.
- underdeserver 3y agoCan you give an example?
- zabzonk 3y agoto be a bit pedantic, i assume the language you a referring to as CPP is actualy C++? cpp to me means the c (and c++) preprocessor.
- oconnor663 3y agoOh I just put up a blog post about this on Monday :) https://jacko.io/object_soup.html https://jacko.io/object_soup.html Agreed that I wish more beginner Rust books had a section about this. The pattern is quite simple, but it's hard for beginners who get stuck to realize that they need it.
- strokirk 3y agoI would have needed this when I started learning Rust! All my early programs were object soups.