In reply to no particular one of the recent answers, but on the topic of the sentiment that one could "replace lifetimes with garbage collection" to create a language that takes some of the features from Rust, but not all,
note that AFAIK most of the unique feature of Rust are also linked to lifetimes. I agree that Rust also has good error handling and algebraic data types, in a way that's not as first-class or fully-embraced in other (not purely functional) languages; but if all that's missing in other existing languages is full support for such things in the standard library / ecosystem, then growing a good ecosystem including an alternative "standard library" in an existing language might still be more straightforward than creating a new language entirely.
Regarding my main point, to name some unique features of Rust: The ownership + borrowing model is clearly linked to lifetimes. Lifetimes are annotations to "help" the borrow checker, nothing more. But they're used for much more than just memory management, so the idea to "replace lifetimes with garbage collection" is flawed to begin with: Ultimately ownership+borrowing is about resource management. Any kind of resource; can be memory, but it can also be anything else.. a file, an open connection, or unique access to a shared data structure. This last point connects with another unique feature of Rust, the remarkably great support for (fearless) concurrency. Rust's story here, evolving around the traits Send
+Sync
is, again, strongly related to ownership+borrowing, precisely because “unique access to a (shared) data structure” is a resource that you can own (or uniquely borrow). The interaction between Send
and Sync
is characterized by distinguishing between owned (or uniquely borrowed) vs. (shared) borrowed data, as evidenced by the T: Sync <-> &T: Send
relation, and the interaction between Send
and Sync
is what powers the compiler's ability to understand the most fundamental synchronization primitives like Mutex
, with its T: Send <-> Mutex<T>: Sync + Send
relation.
Sure, in a Rust (alternative) without lifetimes, but with a (shared) Gc<T>
reference type, you could still technically express some of these relations, e.g. T: Sync <-> Gc<T>: Send
(or perhaps, if this Gc
had Arc
's capabilities like try_unwrap
, then it'd be T: Sync + Send <-> Gc<T>: Send
), but the value of doing so becomes much less useful if you never really own any data anymore. Of Gc<T>
replaces &T
in APIs, then every kind of data of type T
that's supposed to ever be shared (even locally within a thread) needs to be converted into Gc<T>
, an almost irreversible process. This need for Gc<T>
everywhere would be infections, without the convenience that Rust's static analysis features with lifetimes offer, I can hardly imagine how it'd be possible to avoid the need to, realistically, need to replace your whole code with Gc<T>
anywhere; and all the fields that ever need to be mutated would need to become some Cell<Gc<T>>
-like (but thread-safe; basically an AtomicGc<T>
) type. Once that's happened, you would've however turned most or all mutability into "interior mutability", well hidden from static analysis, eliminating any true ownership, and crucially no longer allowing the compiler to prevent any race conditions / data corruption anymore. Sure, there aren't any data races, everything is still memory safe, and you can still use Mutex<T>
if you know you need the synchronization, but most types would be Sync
by default, so nobody ever forces you to use a Mutex
, unless API designers explicitly thought of thread-safety in their API design and explicitly opt out of a Sync
implementation, even though their structs do use AtomicGc<T>
internally.
I feel like I'm describing Java by now (at least in terms of thread-safety). (The opt-out of Sync
is like synchronized
methods in an API, implying that callers will (implicitly) use something that's essentially a Mutex<T>
-style unique access to values.)
To be clear, I'm not arguing against garbage collection here, I'm arguing in favor of lifetimes for applications besides memory management, and against the idea that garbage collection can "replace lifetimes".