7 ms·
Frankly, I'd just use unsafe pointers for the backrefs, and wrap the tree API up in a typesafe layer, and build on top of that. RefCells seem to add unnecessar
by kannanvijayan 9y ago
Frankly, I'd just use unsafe pointers for the backrefs, and wrap the tree API up in a typesafe layer, and build on top of that.
RefCells seem to add unnecessary redundancy here. You'll take a hit for runtime borrow for every pointer chase up the tree. If walking from a leaf to the root is important, you don't want to add an extra compare/branch/set to every pointer chase. Turns a single memory read into a branch, a write, and two reads. Probably about 5x slower at least.
- hashmal 9y agoI'd take a similar approach. After all `unsafe` use cases include the implementation of data structures.
- Animats 9y agoI've argued this issue before. The answer isn't generics, Coq, or some fancy type system nobody will understand or use properly. There are only a few inherent trouble spots in pure Rust code safety. The big two are: - Partially initialized arrays. "Vec" has to be unsafe because growing an array involves uninitialized slots. You just need a way to say "this array is initialized from 0..N only", where N is in a data structure associated with the array. Then you need an operation that says "initialize entry N+1 and update the count". That's all it takes. "Map" could be implemented on top of "Vec", instead of using unsafe code. It would be worth trying this and seeing what the performance penalty is. That may be a premature optimization. - Backpointers. Backpointers have an easily checked invariant relationship with the forward pointer that owns their containing object, but there's no way to tell the language that something is a backpointer.
- a_t48 9y agoA hashmap being implemented on top of vectors is a pretty common implementation. Not sure what Rust uses though.
- __s 9y agoProblem is avoiding having to do Vec<Option<T>>
- Animats 9y agoIf T is a reference type, doesn't Rust do an optimization where <Option<T>>> is implemented by using null pointers?
- kevincox 9y agoYes. This optimization is expected to be expanded in the future but there are currently "NonZero" types. Rust notices this and uses the zero value as the enum descriminant. So in this case the code generated is idential to a nullable pointer.
- sanxiyn 9y agoYes, but that doesn't help when T is not a reference type.
- cesarb 9y agoIIRC, Rust's HashMap uses a single raw vector containing for each entry its hash code, its key, and its value; empty entries have a special hash code as a marker, with the key/value left uninitialized. Also, the hashes are kept together (separate from the rest) for better cache behavior during the linear probing.
- __s 9y agoGood Map implemented on top of Vec: https://github.com/bluss/ordermap https://github.com/bluss/ordermap
- Animats 9y agoVery nice.
- childintime 9y agoThis is a PHP map, correct? It is the one language feature that made PHP stand out from the crowd.
- __s 9y agoPython has followed suit
- catnaroek 9y ago> The answer isn't generics, Coq, or some fancy type system nobody will understand or use properly. The solution is a formal semantics for unsafe Rust, so that programmers can prove that their unsafe Rust code is safe to use by whatever means they prefer. (Mine would be by hand.) --- Reply to dmix: A formal semantics doesn't have to be particularly fancy, although in Rust's case, it will in most likelihood not be straightforward either.
- dmix 9y agoIs that a fancy <x> system that nobody will understand or use properly? (Honest question)
- steveklabnik 9y agoWe intend for it not to be; more on that as we get closer to actually having a model.
- Animats 9y agoProbably. I used to do formal proof of correctness work and headed a project to build a verifier.[1] That stuff is very hard. The partially initialized array thing is an issue of expressive power. You can't talk about that in Rust yet. This is a classic issue. The three big headaches in C around memory safety are "how big is it", "who owns it", and "who locks it". The language lacks the syntax to even talk about those issues. Rust can talk about those, which is a huge step forward. Before you can even consider verifying something, you have to be able to talk about it in some formal language. Preferably the one you're programming in. Having to do formal specifications in a separate language is a huge headache. Been there, done that. There are a few standard trouble spots. I've listed two of them. Most other unsafe code comes from 1) Foreign functions, which can be expected to decline over time as more libraries are implemented in Rust. (How's SSL/TLS in Rust coming along?) 2) "Optimization", which may be premature. This usually consists of bypassing subscript checks. I'd rather have the subscript checks on all the time, and see effort put into hoisting subscript checks out inner loops. (Subscript checks that aren't in inner loops usually aren't significant overhead items.) 3) replicating C/C++ code in Rust. (An early attempt was a transliteration of Doom into Rust, with lots of pointer arithmetic.) Remember, it can blow at any seam. It only takes one buffer overflow to allow an exploit. [1] https://github.com/John-Nagle/pasv https://github.com/John-Nagle/pasv
- pjmlp 9y agoThis is why, as a user of GC languages, I think a bit sad that the ergonomics are so bad for cyclic data structures, that this solution is most likely what the majority will turn to.
- kazagistar 9y agoThr majority never need to write a cyclic data structure, because they can use an existing one from a library.
- pjmlp 9y agoAssuming it covers their use case, regarding API definition and O(n) expectations.