An interesting and very long “experience report” with a safe language for system programming:
I think the most interesting parts for future Rust improvement are:
- Bounds check elimination
- Overflow checking elimination
- Error model
Our model ended up being a hybrid of two things:
Fail-fast for programming bugs.
Typed exceptions for dynamically recoverable errors.
A nice accident of our model was that we could have compiled it with either return codes or exceptions. Thanks to this, we actually did the experiment, to see what the impact was to our system’s size and speed. The exceptions-based system ended up being roughly 7% smaller and 4% faster on some key benchmarks.
In the early days, we experimented with contract analyzers like MSR’s Clousot, to prove contracts. For compile-time reasons, however, we had to abandon this approach. It turns out compilers are already very good at doing simple constraint solving and propagation. So eventually we just modeled contracts as facts that the compiler knew about, and let it insert the checks wherever necessary.
EDIT: pcwalton says some interesting things on Hacker News:
bounds check elimination ends up nightmarish quickly. I think I prefer an approach that fixes the problem at its source, by just encouraging programmers to stop using for loops (which are bad for non-performance-related reasons as well). Note that all of the examples given use for loops; if they were rewritten using iterators, there wouldn’t be a problem. C# has iterators, so the machinery is there; they just need to make it more painful to use a for loop than the iterator alternative.
- The future system/fast Rust code in the wild will probably use some for/while loops, so adding some bounds check elimination will improve performance (but I agree that currently there are more urgent things to implement/improve in Rust, because it’s still young).
- A smart language design (that takes a hint from Ada) should help the compiler eliminate several array bound tests without too much work for the compiler.
- Iterators too have significant disadvantages. In non-release mode the iterators-heavy Rust code is very slow (sometimes 10-20 times slower than release code), and this is a significant problem if you want quick compilation times and “acceptable” performance. Iterators bloat the binary and ask LLVM back-end to remove tons of abstractions. So there are many cases where a simple run-of-the-mill abstraction-light for/while loop is better. I love iterators, and I use them quite often in non-performance-heavy code, but a system language needs to offer very good for loops on arrays.