There's been a fair bit of talk about using this pattern:
struct Nodes {
nodes:Vec<Node>
}
struct Node {
id:u32,
refs:Vec<u32>
}
To implement a 'safe' arbitrary graph in rust.
Due to the single ownership rules, this pattern is usually quite difficult to represent in rust and typically would use raw pointer references (or some abstraction) instead of indexes into the master nodes list.
I believe the pattern was initially was popularized by ixlist::List - Rust
Now... I consider this pattern to actively harmful.
You are effectively implementing a 'virtual heap' to store objects in, complete with virtual raw pointers into that heap; and just like normal raw pointers, it's trivial to end up with null pointers and invalid pointers into that heap.
To be fair, it does work within the bounds of the safety rules, and will prevent the sort of arbitrary memory access errors that unsafe code and raw pointers can result it.
...but:
-
I would argue that this pattern discards even the limited safety that raw pointers provide for a completely unchecked set of custom indexes, and is extremely prone to errors and panics resulting in out of bound access, without any
unsafe
blocks to track where logic audits need to be applied. -
This pattern is fundamentally not thread safe, as you cannot safely share (afaik) a vector between threads (although perhaps you could use a mutex controlled wrapper I suppose?)
-
It is always neccessary to implement this pattern with both a Node and Container type, with the latter storing the instances of the former, and maintaining the synchronization of the index values is not trivial to implement.
I've argued these points to a few people now, so I thought I'd put this thread up here for future reference.
What do other people think?
Does the safety of using the pattern out weigh the negatives?