However, because Rust cares about who owns things, it gets to have all the benefits you get with say RAII types in C++ except seamlessly (in safe Rust anyway).
Imagine you make a Doodad, like you call a constructor for it maybe, or there's some call somewhere that gives you a Doodad. OK. Now you put the Doodad in a Hashtable of Doodads. Well, is that still your Doodad? Are you responsible for ensuring it is properly cleaned up at some point? Or does the Hashtable now take responsibility for it? If somebody looks in the Hashtable, do they get back the Doodad? Now is it no longer the Hashtable's responsibility?
Rust systematically has answers to all these questions, which permeates the language and its ethos, in exchange it gets to have really nice properties.
> the Java GC (still in 2022) is often a major headache in production wrt latency when system is under load.
Can you say a bit more about your experience regarding this? In my experience, it is either not due to GC, because it is really hard to make the G1 GC miss its target pause time, or there is an easily debuggable function creating way too much object, and the fix is often trivial.
Like, the JVM has the state-of-the art GC implementations.
Rust doesn't have a mark-and-sweep GC. It has "automatic" memory management through static analysis. Rust's memory management is done by the compiler automagically inserting free() in the same places that you would put it manually in C.
I would add that it inserts free similarly to C++’s RAII, and it also have reference counting wrapper type which will free at runtime. Reference counting makes different tradeoffs to mark-and-sweet GCs, they usually have worse throughput, but better latency (when they are shared between threads, every new/lost reference does an atomic increment/decrement which is very expensive and happens on the working thread. Java’s GC for example can amortize this cost by doing the work almost completely in parallel)
It's not quite RAII, because it's not scope-based. Rust has exclusive ownership with moves by default, so it avoids having a concept of an accessible moved-out-of value that still has to run destructors redundantly.
It's not based on reference counting. It's possible to implement reference counting in user code (like C++ shared_ptr), but that is still notably different than languages that use reference counting as their primary memory management strategy (like Swift or CPython). In Rust reference count increases are manual, and refcounted values can be borrowed and safely passed around without updating the reference count.
Genuinely curious here: the Java GC (still in 2022) is often a major headache in production wrt latency when system is under load.
How's the Rust GC in that regard?