sans-seraph
Rust quietly has several other features in order to improve the quality-of-life of its ownership model. Two examples: if you have a mutable reference then Rust will coerce it to an immutable reference if one is required, and if you have a mutable reference then Rust will transparently re-borrow it when calling functions that accept mutable references in order to allow you to use the mutable reference more than once despite the fact that they do not implement Copy.
It is possible to turn any Rust warning into an error with the use of the `deny` attribute. In addition it is now possible to configure the behavior of lints in the `lints` section of Cargo.toml.
As a Rust advocate in this domain I have attempted to temper the expectations of those driving this proposal with due respect to the feasibility of automatic translation from C to Rust. The fundamental obstacle that I foresee remains that C source code contains less information than Rust source code. In order to translate C code to Rust code that missing information must be produced by someone or something. It is easy to prove that it is impossible to infallibly generate this missing information for the same reason that scaling an image to make it larger cannot infallibly produce bits of information that were not captured by the original image. Instead we must extrapolate (invent) the missing information from the existing source code. To extrapolate correctly we must exercise judgement and this is a fallible process especially when exercised in large quantities by unsupervised language models. I have proposed solutions that I believe would go some way towards addressing these problems but I will decline to go into detail.
Ultimately I will say that I believe that it is possible for this project to achieve a measure of success, although it must be undertaken with caution and with measured expectations. At the same time it should be emphasized it is also possible that no public result will come of this project and so I caution those here against reading too much into this at this time. In particular I would remind everyone that the government is not a singular entity and so I would not interpret this project as a blanket denouncement against C or vice versa as a blanket blessing of Rust. Each agency will set its own direction and timelines for the adoption of memory-safe technologies. For example NIST recommends Rust as well as Ada SPARK in addition to various hardened dialects of C/C++.
Similarly in Rust, serious programs will use writeln rather than println, and will receive the standard compiler warning if the Result produced by writeln is ignored.
In addition Rust was born from Mozilla and imitates Firefox's rapid release schedule of one release per six weeks. This does not mean that Rust releases are substantial or that they are traumatizing, only that they are frequent. The contract with users is that Rust releases must be painless so as to not fatigue users and discourage them from upgrading. The success of this painless upgrade strategy is proved by the fact that library authors are so quick to upgrade, as mentioned.
This is in contrast to other languages where historically a new version of their compiler might only be released as infrequently as once per three years. It seems that these languages have begun taking queues from Rust as even Java now releases once per six months.
To give an example, in the past week I have ported over a thousand lines of C code to a successor written in Rust. During development compilation errors were relatively frequent, such as size mismatches, type mismatches, lifetime errors, etc. I then created a C-compatible interface and plugged it into our existing product in order to verify it using our extensive integration test suite, which takes over 30 minutes to run. It worked the first time. In order to ensure that I had not done something wrong, I was forced to insert intentional crashes in order to convince myself that my code was actually being used. Running that test suite on every individual change would not have yielded a benefit.
The broader topic of whether it is safe, or wise, to cast between pointers and integers in general is an area of active research. Ralf Jung's blog is required reading on this topic: https://www.ralfj.de/blog/2022/04/11/provenance-exposed.html
Because A and C only jump to B it is possible to structure this using only loops and one boolean. Let us use Rust to demonstrate as it lacks GOTO:
let mut a = true;
loop {
loop {
if a { // state A
match scan() {
0 => { write(1); right(); break }
1 => { write(3); left(); break }
2 => { write(1); right(); return }
3 => { write(2); right() }
}
} else { // state C
match scan() {
0 => { write(3); right(); break }
1 => { write(1); left(); break }
2 => { write(3); left() }
3 => { write(2); right() }
}
}
}
a = loop { // state B
match scan() {
0 => { write(2); left(); break false }
1 => { write(3); right() }
2 => { write(1); left(); break false }
3 => { write(2); right(); break true }
}
}
}
Of course it is possible to rewrite this as a single loop if you are willing to accept two bits of extra state rather than one.