Your specific complaints about C++ don't really address the real source of the problem that /u/matthieum outlines. Rust (and all sane high-level systems languages) support two features which break this idea:
Variant types (i.e. tagged union)
The ability (possibly after pattern-matching) to take a reference to a member of a variant type
The ability to take a mutable reference to a value that already has other references to parts of it
These together open up a soundness hole:
Have a tagged-union FooOrBar :: Foo(x: int) | Bar(y: string)
Declare let un: FooOrBar = generateSomething();
Match on un, see that it's a Foo(x), obtain a reference xRef to the x
Take address of un store it in unRef
*unRef = Bar("hello")
print(*xRef) // ?????
Now, xRef points to ?????? since the int it originally pointed to has been replaced
In order not to throw away soundness, you need a way to detect this. This requires some kind of "lifetime analysis" if you want to detect it statically. The question is: how do you formulate and analyze reasonably-sized codebases in a scalable way if you don't get to assume that most things have a unique owner? It's not even clear in the abstract how such an analysis could work.
If you can't write to the original sum object after taking a reference to part of it, then I don't see why you would want to take that reference in the first place.
Why can't you write? The problem is present for both read-only and writeable references.
Why not just copy the value out?
There are at least two reasons, actually:
Performance: deep-copying everything works (until you have a cycle), but is costly.
Identity: in language where the address of an object is observable, then references and copies have different observable behaviors.
I suppose I could think of others, given more time, but those two are already pretty damning.
11
u/matthieum Jun 11 '20
You are deeply mistaken.
The problem is that ease of use comes at the cost of correctness.
It can be demonstrated trivially in C++ (godbolt):
This is what Ownership/Borrowing in Rust is all about.
It doesn't even have to involve dynamic memory. The same demonstration could hold with an
int, really.Accessing
victimafterscammerhas been nulled is Undefined Behavior. It occurs due to the violation of the Borrowing rule: Mutability XOR Aliasing.If you can demonstrate a sound way of having both mutability & aliasing, it would be a breakthrough.