Hacker News new | past | comments | ask | show | jobs | submit login

Oh, nice. It's hopeless for C/C++ for legacy reasons, but D - that could work.

Two memory safety related things to consider. Rust needs unsafe code to do these things.

1) Backpointers. Rust's ownership system doesn't allow backpointers, at least not without reference counts. So some standard data structures, such as doubly linked lists and various types of trees, can't be coded in safe Rust.

A backpointer is defined by two objects which have an invariant locking them together. If you could talk about a backpointer in the language, and tell the compiler where its forward pointer is, you could enforce the necessary invariants. If A contains a pointer to B, B's backpointer must point to A. Any code which modifies either of those pointers must maintain the consistency of that relationship. That's checkable at compile time.

This fits well with ownership. A owns B. B's backpointer is a slave. All that's needed is type syntax which says "backpointer b.reff always points to my owner."

There are lots of interesting cases to be worked out, especially around destructors. Those are worth checking at compile time, because people get them wrong. It's really nice if you can be sure that a data structure always tears itself down cleanly when you drop the link to its root.

2) Partial initialization. Collection classes which allow growth are hard to do in safe code, because they require arrays which are partially initialized. It should be possible to talk about partially initialized arrays in the language. Maybe some predicate such as "valid(tab,n,m)" indicating that array tab is valid from n to m inclusive. You can't access an element outside the n..m range. The checker for this needs to know some simple theorems, like "valid(tab,n,m) and valid(tab,m+1,m+1) implies valid(tab,n,m+1)". Then it can track through a loop and verify that the array is initialized for the given range.

Somebody will complain that they want sparsely initialized arrays containing types that really need initialization. Tell them no.




Backpointers can be more than one step away, for example with a circular linked list, or with a directed (not-acyclic) graph. It's harder to see how to enforce these more complex invariants at compile time (but maybe not impossible).


That's where the language designer has to say "no". Trying to make ownership semantics work for arbitrary graphs is too much trouble.

I had to deal with this once writing a 3D collision detection system. Objects were convex hulls, with vertices, edges, and faces, all pointing to each other. I had an implementation in C to look at, and it was a mess. Ownership was so tangled that they couldn't delete objects.

So I rewrote it in C++, with each object having collections of vertices, edges, and faces. All links between them were indices, not pointers. Lots of asserts to validate all the consistency rules. Easy to delete, and much better cache coherence. Chasing pointers to tiny objects all over memory belongs to the era when cache misses didn't dominate performance.

So that's the answer. Some data structures are too complex for ownership semantics. So do them another way and have all the parts be owned by some master object.


> Oh, nice. It's hopeless for C/C++ for legacy reasons, but D - that could work.

What in particular do you think would be impossible in C++ for legacy reasons?

From a very high level it seems to me that all the necessary ingredients of this solution are available in C++ (> C++11) as well. There are pointers, smart pointers, references, constness and move semantics for the ownership and borrowing. There are [[attributes]] for the method-selective opt-in.

There is of course always the argument of not making C++ compilers even more complex. But is there some actual technical limitation in fitting the same idea into C++?


You need to prevent copy-paste compatibility with C like code, which is kind of possible with static analysers, but even then only over the source code you have access to, forbading any 3rd party libraries.

So unless you get the buy-in from the whole team, it hardly works across big projects.


> Maybe some predicate such as "valid(tab,n,m)" indicating that array tab is valid from n to m inclusive.

That can be done with a Vec in Rust (n is vec.len() and m is vec.capacity()).


Vec is an unsafe built-in. If you can talk about partially initialized arrays, you can write Vec as safe code.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: