Atomic ref-counts can actually have a surprising amount of overhead in many multithreaded scenarios, so much so that going back to raw pointers over shared pointers in C++ for some use cases of passing pointers around can provide a huge win.
let data = Arc::new(Mutex::new(Data::new()));
And if you want a mutable static global that's accessed across threads, you'll need something like: lazy_static! {
// 0 -> None
// 1 -> Circles
// 2 -> Bezier
static ref DRAW_ON_TOUCH: Arc<Mutex<u32>> = Arc::new(Mutex::new(0));
}
I love Rust but it is making easy things harder than they need to be.Also, the Arc isn't needed in lazy_static: just a mutex is enough for mutability, the sharing (which is what Arc controls) comes from being a static.
Of course. Rust is memory safe. The compiler will prevent you from sharing non-thread-safe reference counted objects between threads.
This is a significant advantage over C++, where the compiler offers no such protection and so the typical solution is just to use atomic reference counting (shared_ptr) everywhere.
To learn more about this, look here: https://doc.rust-lang.org/beta/nomicon/send-and-sync.html
Separately emotionally I feel different about Arc<T> because all the counting is explicit and I see it. Understanding where shared_ptr<T> in C++ counts however can be quite a challenge, even if you consider yourself proficient with C++.
Here's Niko Mastakis talking about a case where that happened to him (I think): https://youtu.be/lO1z-7cuRYI?t=4m
"... trusting the programmer is fundamentally wrong, no matter the programming language"
They could also happen if you used non-thread-safe reference counting on a thread-safe object. Now this seems to be rare in practice, because non-thread-safe reference counting is unusual. If it became more prevalent, however, I could see it happening.
As beneficial to your argument as it would be for that change to be the definition of "software", I don't think that's likely.
I am well aware of the pressure on developers to get requested feature done quickly. But the vast majority of bugs that get shipped would be easily prevented by more thorough processes. All those projects writing highly reliable software demonstrate this. But the price tag has a few zeroes appended as a result.
Rust’s type system is arguably one of them.
Type systems are tools that simply the process of checking that you do not mangle data by applying the wrong instructions to them. They didn't come out of nowhere.
It also shows in the cost of building the software. Most software companies aren't willing to pay the cost of that process. Like it or not, you will almost certainly interact with software written by these companies, either directly or indirectly.
Yes. It errors at compile time (`std::rc::Rc<i32>` cannot be sent between threads safely)
No, not unless the object is actually shared among multiple threads.
About the refcounts: since the counting is explicit (calls to clone()) they at least in my experience don't really show up. Most of the refcounted objects I deal with bump the refcounts once when some task spawns and decrements it when it ends. I have yet to see refcounts to change in hot code paths.
//EDIT for your edit:
> Edit: Forgot about handles. Ugh. Completely unacceptable when you want to grow your tree data structure and you have to do a realloc and basically copy every node.
Sure, but that's not my point anyways. At any point you can fall down to writing unsafe code and building a safe abstraction on top of it. This is to help developers not run into walls. I don't think that handles are the best thing invented but I don't think "well you can't do that in Rust until we some time in the future" and not provide an alternative is a particularly good suggestion.