Hacker News new | ask | show | jobs
by verdagon 2235 days ago
Can you explain why multiple mutable pointers is bad practice?

I understand the benefits and the risks of them, and understand how Rust prevents both, but I dont yet understand why it's bad practice, and am interested to learn why.

2 comments

The one that affects you as a programmer most is Iterator invalidation. Iter borrows from the vector, you mutate the vector, iter blows up. Simple really. But a lot of code is like this. Borrow from hashmap, insert into hashmap, the slot gets moved around and your pointer is now invalid. That’s just vectors and hashmaps; imagine the possibilities in a much more complex data structure.

There are compiler optimisations you can do if compiler knows about aliasing, but that’s not so much a software authorship problem. There are some curly problems with passing aliased mutable pointers to a function written for non-aliased inputs, like memcpy and I imagine quite a lot of other code.

But common to all of these things is that it’s pretty hard to figure out if the programmer is the one who has to track the aliasing. In hashmap pointer invalidation, your code might work perfectly for years until some input comes along and finally triggers a shift or a reallocation at the exact right time. (I know this — I recently had to write a lot of C and these are the kinds of issues you get even after you implement some of Rust’s std APIs in C.)

Is this still bad practice if the container can detect when this happens, like Java's? Not saying that it always has to throw like Java, I could imagine implementing a weak iter which we'd check before each operation.
I feel like this is something common c++ developers know, and it's not worth all the baggage to tag it. You just control the iterator inside the loop instead of in the loop declaration.
Because it leads to hard to understand code.

If N unrelated (or loosely related) things can mutate the same object, then you get a O(x^N) explosion of potential mutation orders and in order to understand that, you need to understand all the (sometimes complex) time-relationships between these N objects. This gets even much worse when some of these objects are also pointed from M other objects...

On the flip side, in case of using a simple unique_ptr (or a similar concept), this trivially reduces to a single sequence of modifications.

Dont we in Rust still conceptually modify the vector multiple times, just through different means (usually a generational index or something)?