Hacker News new | ask | show | jobs
by 235235235235 1467 days ago
What does Rust offer over modern C++ with smart pointers and RAII?
4 comments

- sane generics

- better type system

- better type inference (bidirectional)

- better/standardized package manager

- better error messages

- memory safety

- thread safety

There are downsides but it’s an improvement on balance. I use both extensively.

> sane generics

> better type system

> better type inference (bidirectional)

how do you quantify "sane" and "better" here ?

Protection from data races and invalid pointers maybe?
Rustian Safety

Rustian Garbage collection

> Rustian Garbage collection

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?

Rust isn't a Garbage Collected language.

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.

Have you ever wondered what a "moved-from" object [0] in C++ contains? In Rust, such objects are inaccessible due to enforcement of the compiler. In C++, they are accessible. Have you ever wondered what performance implications that has? Have you looked into what the C++ standard tells us about "moved-from" STL objects, what state they are in?

[0] e.g. `b = std::move(a)`, what is in `a` now?

There are good use cases for requiring the moved object to still be valid and accessible, such as when memory lifetimes are decoupled from object lifetimes. It enables some optimizations. The specific state depends on the design of the type and its use case.