Sure, that does seem to be a race condition that can crash. I'm not sure how valuable this example is though, because it's not very intricate at all: a Weak reference can be invalidated (duh!)
The fix is trivial: just use an Arc instead of a Weak. In addition, `upgrade().unwrap()` should be a sizable red flag (like any unwrap, really) since fallibility is kind of the entire thing of Weak.
But Weak can be needed in case you have self-referential structures, right?
I was wondering about this in the context of the C++ programmer in post above who likes to use both new/delete and malloc/free in his code.
Sure, Rust will give him far fewer ways to screw up. But if he can't be asked to at least not use malloc/free in C++, he probably won't be too careful about unwrap() either?
My point here is mainly that a good programming language won't make good programmers out of bad ones.
> But Weak can be needed in case you have self-referential structures, right?
Well, technically, no, you can just use Arc and leak memory all over the place :^) but that's not very useful either. Most self-referential structures need some kind of "owning" thing too though. For example, a graph could use Weak for the edges, but in order to keep vertices alive you need e.g. a Vec<Arc<Node>>. Then, if upgrading fails, you know that your edge leads to a deleted vertex (and as such should be considered nothing, hence Option).
> Sure, Rust will give him far fewer ways to screw up. But if he can't be asked to at least not use malloc/free in C++, he probably won't be too careful about unwrap() either?
There's one big advantage of messing up with unwrap vs malloc/free: unwrap 'only' crashes your program (and can even be caught in some scenarios), whereas use-after-free can do literally anything. Unwrap is also much easier to debug because you usually get a clear stack-trace, and the program semantics have been well-defined at all points.
> My point here is mainly that a good programming language won't make good programmers out of bad
ones.
Very true! But I think the point of Rust advocates tends to be more along the lines of "a bad programming language makes a bad programmer out of a decent one". It is very easy to misuse C++, so mistakes are made with it way more often. 'Dangerous' constructs do exist in Rust, but are generally far less pervasive, making it easier for the programmer to understand what they are doing.
Saying Rust has no benefits over C++ because you can mess up in both is like saying that anti-lock brakes are useless because you can still understeer by pressing the accelerator too hard (sorry for the car analogy, I had to). Preventing entire classes of mistakes is valuable, even if other classes are still possible. (If it's worth the cost is of course another question. My personal opinion is yes, although that's especially for memory safety and a bit less for race safety.)
Sorry, that wasn't my intent. It was more to point out that bad programmers are surprisingly inventive when it comes to write bad code. New languages are an improvement, but not a panacea.
The fix is trivial: just use an Arc instead of a Weak. In addition, `upgrade().unwrap()` should be a sizable red flag (like any unwrap, really) since fallibility is kind of the entire thing of Weak.