Karl Schultheisz

Wait, Maybe Not Rust

Published (updated: ) in Uncategorized.

I don’t like to come to conclusions prematurely, but the fact is that most human decisions are made from the gut, before we become aware of it, despite our conscious rationalization. One such decision is whether to develop Recursyn using C or Rust. Here’s the rationalization.

Rust is the “most loved” programming language. Doesn’t that mean it’s a good choice for new systems programming projects? Even professional Rust consultants are skeptical:

Five years old, Rust is definitely a young language. Even though its future looks bright, I will bet more money on “C will be around in ten years” than on “Rust will be around in ten years” (See Lindy Effect).

Aleksey Kladov – Why Not Rust?

Let’s not get too hung up on terminology, but I think Rust is speaking to the issue of code quality on their front page:

Rust’s rich type system and ownership model guarantee memory-safety and thread-safety — enabling you to eliminate many classes of bugs at compile-time.

Why Rust? Reliability.

Michael Feathers, one of the early proponents of test-driven development (TDD), later concluded that TDD is but one of many paths to code quality. From his studies of other effective code quality control approaches, many of which lack testing, he noticed that each got programmers thinking deliberately. Let’s call this Feathers’ Razor: the proposition that the simplest explanation of quality code is clear thinking.

Rust’s static analysis is advertised as a code quality control; type and borrow checking are tests built into the compiler. So Feathers’ Razor applies. Rust’s static analysis, by itself, is both unnecessary for memory safety and insufficient for low defect density; there are many examples of C programs that lack bugs, and memory bugs in particular. I am reminded of a flippant passage from Coders at Work:

Seibel: So when there’s a security breach that turns out to be due to a buffer overflow, what do you say to the criticism that C and C++ are partly responsible—that if people would use a language that checked array bounds or had garbage collection, they’d avoid a lot of these kinds of problems?

Thompson: Bugs are bugs. You write code with bugs because you do.

Choosing a software quality control approach is a matter of what works for programmers. While programmers have different preferences that might affect what approach would help them write low-defect code, human beings all are subject to a relatively limited working memory and a tenuous ability to concentrate, so any code quality approach has to operate within those limits.

I read somewhere that a five-second interruption is enough to break a person’s concentration. How fast is your edit-compile-run loop? (Tools such as entr can speed this up.) If any part of the codebase requires the reader to remember more than seven random facts simultaneously, the programmer starts writing bugs.

While slow compilers are the only game in town for embedded C, they’re at least faster than rustc. TCC seems to be one of the few C compilers that can satisfy the time constraint for million-line codebases; unfortunately, it only targets x86 processors.

Most of this has very little to do with the choice of programming language. Rust introduces constructs that are useful for systems programming, but it also introduces constructs that are useful for writing extremely complex code. If Rust is ultimately about code quality, then it has made a doubtful tradeoff.

I think Rust can be effective in the hands of programmers who have a healthy fear of its pitfalls. I doubt that the Rust programmers I’ve encountered have such a fear.

I think Rust is the “most loved” programming language because it tells programmers something they want to hear; it isn’t their fault that their codebase is full of memory errors, but the tool’s. And there might be some truth to that, but it de-emphasizes the human factors are even more relevant to defect density. Rust “enabl[es] [programmers] to eliminate many classes of bugs at compile-time”, but this says nothing about the number of bugs. What is gained if Rust trades us one class of bugs for another?

Thus I conclude that Rust, and any programming language, cannot be in itself an approach to code quality. There is no programming language that forces clear thinking. Human beings can think clearly when they are not juggling too many random facts simultaneously and aren’t being interrupted. Even a hypothetical language that compiles 1 MLoC/s and reduces program complexity by design can’t guarantee clear thinking. A programming language isn’t in a position to solve this problem. But a programming language can be designed not to be an obstacle to quality.

As a founder of a new company, I want to set that company on a strong foundation. Rust’s support for microcontroller peripheral drivers is incomplete, which tightens my timeframe. In an uncertain world, it feels more secure to be sparing with my resources.

I discovered libopencm3 recently. A high-quality C codebase with over a decade of development history, it advertises complete support for STM32 microcontrollers. This alone is reason enough to switch hardware platforms. And the fact that it’s written in a language I already know? I can feel the risk dwindling.

This is the gut reaction. I can try to temper it with conscious moderation, but it’s not my first rodeo. Recursyn will be written in C.