3 ms·
This stack would catch _most_ problems, but not necessarily at compile time. It's unsound, because it's still possible to write data races. And it's possible
by andrewaylett 5y ago
This stack would catch _most_ problems, but not necessarily at compile time. It's unsound, because it's still possible to write data races. And it's possible that two components, each on their own correct, combine to make something that isn't correct.
Rust's borrow checker makes it impossible to write code containing a data race. It does this by only accepting a subset of possible safe programs, but this is (or at least may be) a reasonable trade-off due to the guarantee you get.
It's not that you can't write safe code in C++, but you're always at the mercy of your validation to try to have confidence that you've actually managed to do what you set out to do. While Rust obviously doesn't preclude bugs at all, but it does enforce that you _can't_ write a certain class of previously-prevalent bugs.
I think this blog post from Mozilla does a good job of what that means in practice: https://blog.rust-lang.org/2017/11/14/Fearless-Concurrency-In-Firefox-Quantum.html https://blog.rust-lang.org/2017/11/14/Fearless-Concurrency-I...
- jandrewrogers 5y ago> It does this by only accepting a subset of possible safe programs, but this is (or at least may be) a reasonable trade-off due to the guarantee you get. I think this is correct but would expand on the nature of the tradeoff. Rust only accepts a subset of safe programs, and can express any program in the abstract, but that subset may not contain the optimal safe program. In some cases, differences in practical performance between the expressible safe program and the optimal safe program can be quite large. Modern C++ cuts a tradeoff along a different dimension: it will accept unsafe rubbish but the optimal safe program is also expressible in virtually all cases. C++ has large niches where it can express optimal safe programs, and where this optimality is important, that Rust cannot. Obviously it is incumbent on the programmer to write safe code in C++, but the flexible type system is more capable of enforcing safety than I think people expect, particularly in recent versions of C++.
- andrewaylett 5y agoAgreed. But there's optimal and there's "optimal" -- by restricting the developer, we open up more opportunities for the compiler to optimise the code (for all that Rust isn't necessarily able to take advantage of these opportunities yet) and a judicious use of `unsafe` may even help us to build an abstraction that gives us the optimal program anyway. Crucially, code that uses unsafe is still no less safe than ordinary C++ code. From my days as a compiler engineer, I definitely prefer to write clear code and fix the compiler rather than try to convince the compiler to produce the right result by mangling code. And to build my control logic as an abstraction, even if it's only going to be used in one place, so it can be verified separately from the business logic it drives.
- sk1459 5y ago>impossible to write code containing a data race https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=Rust+data+race https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=Rust+data+r...
- andrewaylett 5y agoOK, I'll grant I should have added scare quotes to "impossible". A quick check suggests that (as would be expected) they're caused by `unsafe` blocks. Specifically, by the developer claiming that a value was safe to send to a different thread while it actually wasn't. One thing to note is that these bugs neutralised the compiler's validation is these specific cases -- allowing, rather than causing, races. Using unsafe means the developer needs to ensure they maintain the invariants themselves within the unsafe block, while in C++ one has to maintain these invariants in _all_ code.