Most of the performance penalty for the languages you mentioned is because they're dynamically typed and interpreted. The GC is a much smaller slice of the performance pie.
In native-compiled languages (Nim, D, etc), the penalty for GC can be astoundingly low. With a reference counting GC, you're essentially emulating "perfect" use of C++ unique_ptr. Nim and D are very much performance-competitive with C++ in more data-oriented scenarios that don't have hard real-time constraints, and that's with D having a stop-the-world mark-and-sweep GC.
The issue then becomes compatibility with other binary interfaces, especially C and C++ libraries.
> With a reference counting GC, you're essentially emulating "perfect" use of C++ unique_ptr.
Did you mean shared_ptr? With unique_ptr there's no reference-counting overhead at all. When the reference count is atomic (as it must be in the general case), it can have a significant and measurable impact on performance.
You might be right. Though with the way I design software, I'm rarely passing managed objects via moves to unrelated scopes. So usually the scope that calls the destructor is my original initializing scope. It's a very functional, pyramidal program style.
Definitely true! Probably add Swift to that list as well. Apple has been pushing to use Swift in WebKit in addition to C++.
Actually Nim2 and Swift both use automatic reference counting which is very similar to using C++’s SharedPointer or Rusts RC/ARC. If I couldn’t use Nim I’d go for Swift probably. Rust gives me a headache mostly. However Nim is fully open source and independent.
Though Nim2 does default to RC + Cycle collector memory management mode. You can turn off the cycle collector with mm:arc or atomic reference counting with mm:atomicArc. Perfect for most system applications or embedded!
IMHO, most large Rust project will likely use RC or ARC types or use lots of clone calls. So performance wise it’s not gonna be too different than Nim or Swift or even D really.
> IMHO, most large Rust project will likely use RC or ARC types or use lots of clone calls. So performance wise it’s not gonna be too different than Nim or Swift or even D really.
I do not think so. My personal experience is that you can go far in Rust without cloning/Rc/Arc while not opting for unsafe. It is good to have it as default and use Rc/Arc only when (and especially where) needed.
Being curious I ran some basic grepping and wc on the Ion Shell project. It has about 2.19% of function declarations that use Rc or Arc in the definition. That is pretty low.
Naive grepping for `&` assuming most are borrows seems (excluding &&) to be 1135 lines. Clone occurs in 62 lines for a ratio of 5.4%. Though including RC and ARC with clones and that you get about 10.30% vs `&` or borrows borrows. That's assuming a rough surrogate Rc/Arc lines to usages of Rc/Arc's.
For context doing a grep for `ref object` vs `object` in my companies Nim project and its deps gives a rate of 2.92% ref objects vs value objects. Nim will use pointers to value objects in many functions. Actually seems much lower than I'd would've guessed.
Overall 2.19% of Rust funcs in Ion using Rc/Arc vs 2.92% of my Nim project types using refs vs object types. So not unreasonable to hold they have similar usage of reference counting vs value types.
In native-compiled languages (Nim, D, etc), the penalty for GC can be astoundingly low. With a reference counting GC, you're essentially emulating "perfect" use of C++ unique_ptr. Nim and D are very much performance-competitive with C++ in more data-oriented scenarios that don't have hard real-time constraints, and that's with D having a stop-the-world mark-and-sweep GC.
The issue then becomes compatibility with other binary interfaces, especially C and C++ libraries.