> They see all of this business with lifetimes and ownership as a dirty mess that Rust has had to adopt because it wanted to avoid garbage collection. But this is completely backwards! Rust adopted rules around shared mutable state and this enabled it to avoid garbage collection. These rules are a good idea regardless.
I'm not sure that this is true. Lack of garbage collection and management of shared mutable state are implemented by partially overlapping aspects of the borrow checker.
If Rust eliminated lifetimes and ownership but maintained its rules for & and &mut, it would require garbage collection but still control mutability. On the other hand, if Rust allowed &mut freely and retained lifetimes, then you could have mutable shared state but no need for garbage collection.
The only doubt I have is, maybe freely permitting &mut would make lifetimes unsound? I haven't used Rust enough to be sure.
They're not quite that independent, because the choice of memory management strategy relies on the aliasing rules. But (as the post argues) the aliasing rules don't rely on the memory management strategy.
The guarantee that &mut is unique enables mutations to change the "shape" of an object in memory- e.g. reallocating a Vec to grow it, or overwriting a Box with a new one and freeing the original, or overwriting an enum/union in-place with a different variant.
If &mut were not restricted in this way, then this "eager" memory re-use could cause other references, into the interior of the shape, to dangle. But this is how Rust manages memory- if there may be other references to the old memory, when is it safe to free it, and reuse it with a potentially different type? Lifetimes don't help you here, unless you make them powerful enough to re-encode the same old aliasing rules!
It's important to note that this is not only about heap allocations. The enum/union case, for example, is entirely in-place in Rust. So even if you switch to an arena or type-segregating allocator, and accept that the old references might point to stale or now-unrelated values, you still haven't recovered memory safety. You need to keep the old value, with its old type, in place in memory simultaneously.
GC provides memory safety by making it practical to forbid these kinds of memory layouts to begin with- the program cannot eagerly free an old backing array or heap object, nor can it overwrite an enum in-place. Instead it can only mutate the references themselves, leaving the old value alone for any other references that may still exist.
There is a middle ground, where a language could allow shared mutability with more compact memory layouts, but it requires a different set of restrictions: like GC, no references to array elements or Box/enum/union fields; without a GC, working with these values requires deep copying them. Languages like Java already do this, but only for primitive types where the copy can be atomic. (Or you could use something GC-like, such as reference counting and/or copy-on-write.)
The point of the post is that the Rust approach to memory management is not the only thing that the aliasing rules gives you, because they also aid in local reasoning about your programs, regardless of your approach to memory layout and allocation.
I'd tend to agree with your understanding of the path Rust's development took, but it is certainly not clear cut which led to which. I am certainly willing to be corrected (my memory is getting rough at this point in my life), but I remember the bifurcation of mutability and alias-ability being present in Graydon's original pitch deck, which existed as a prototype with garbage collection being expected to exist. Then after some work, I thought the language devs realized that with some extra rules, which became the lifetime semantics, there was a feasible method for not requiring a garbage collector, but still remain fairly free of manual/explicit memory management by developers.
I'm not sure that this is true. Lack of garbage collection and management of shared mutable state are implemented by partially overlapping aspects of the borrow checker.
If Rust eliminated lifetimes and ownership but maintained its rules for & and &mut, it would require garbage collection but still control mutability. On the other hand, if Rust allowed &mut freely and retained lifetimes, then you could have mutable shared state but no need for garbage collection.
The only doubt I have is, maybe freely permitting &mut would make lifetimes unsound? I haven't used Rust enough to be sure.