I have a confession! Rust has made me greedy for correctness.
We have a project written in C that is ~30 Kloc across more than 150 source and header files. The level of scrutiny that I need to give each of those 30K lines matches that of the lines of unsafe
Rust that I have in any of my projects; two dozen, maybe? Regardless, that's four orders of magnitude fewer things to worry about. Honestly, I still don't know where to begin with attempting to prove any correctness on this project. It appears an insurmountable task.
Dynamic languages? How about 57 Kloc of Python? I might not have to worry about memory safety in those lines, but I still have to worry about data races. And even worse, I have to worry about runtime exceptions with the type system.
There's also 20 Kloc of JavaScript here, another 25 Kloc of Python over there. Rinse and repeat for hundreds of git repos... And frightening, 40 Kloc of YAML! Oh dear. "Configuration as code", as they say.
So I'm greedy about correctness, and yet I cannot prove any of the C, Python, JavaScript, or YAML is "correct" in any sense beyond existing test coverage. Which I might add, because we live in the real world, test coverage is poor. Even though some projects routinely hit 100% "test coverage", that doesn't mean they test all valid input or config permutations. Fuzz testing is only something I dream about in a production code base.
And with Rust? I get to be the best kind of lazy! The compiler proves correctness of the code, I prove correctness of the logic with tests (for some value of "coverage"), and then I get to worry about other things that actually matter. (Like trying to figure out how to prove all this other code is correct! lol)
I have another confession! Rust changed my mind about error handling.
As it turns out, handling errors is not optional. We like think that we can just ignore things like socket timeouts, or file-not-found and the like. Truth is, error handling must be enforced for them to actually be handled. And Rust does a decent job, here. It even offers an escape hatch to catch-all errors into oblivion if you can afford to be negligent. But putting error handling right in the developer's face is a really good thing.
And it shows from the rock-solid stability of the services I've put into production with Rust. "Set it and forget it" is real. I have another service written in Python that is fairly solid. It only took 6 years of testing, fixing uncaught exceptions, and a lot of trial-and-error to get it to its current state. For comparison the Rust project was written in about 4 weeks. (Not shown here is the actual scale of utilization, but that's a different calculus.)
I have yet another confession! Rust proved to me that high-level abstractions can be used in resource constrained environments.
Prior to Rust, I used C for several years in the embedded space. Not C++, mind you. Just plain ol' C99 and C89 before that. These kinds of projects are small by definition, but they can be demanding from a different perspective. They may require a level of cleverness that you don't normally see in service-oriented systems or your typical end-user applications that run on super computers with billions of bytes of memory.
With Rust I can have these really nice abstractions like algebraic types and sane error handling. I'm also given the warm and fuzzy feeling that my code doesn't unintentionally rely on undefined behavior, that it is memory safe and data-race safe. (Exception handlers are tricky!) If I have a heap I also get access to growable collections like vectors, hash maps, and sets. Even if I don't have a heap, I can still used fixed-size variants of these collections on the stack. I can write async code using Futures without multiple stacks or multiple threads.
It may be important to point out that there are subsets of other languages that target embedded systems; micropython, tinygo, low.js, espruino, etc. I say "subset" in the sense that you shouldn't expect JavaScript to run like V8. And as a learning tool, these are great. But I am not targeting little IoT gizmos. I am building games that run on bare metal. Bare metal from the mid-90's, but no less bare metal. Having the kinds of compiler guarantees provided by Rust is incredibly important to meeting my performance and personal sanity goals.
In my day job, these qualities translate surprisingly well to large super computers and distributed systems. I have all the same basic tools that are known to work in resource constrained environments. On the one hand, I could use other frameworks or language features that use copious amounts of memory and CPU time. On the other hand, I could reap the benefits of zero-cost abstractions even though it's arguably unnecessary on these gargantuan machines. It makes sense when you understand that performance is money, memory is money, and latency is money.
In other words, if it runs on 25-year-old hardware, it can certainly run on modern hardware. And it will probably run more than 100x more efficient.