If one thing has really followed me through 2019, then it was Rust. I’ve spent time with the language on and off for the whole year, writing parts of a NES emulator, a small sokoban clone for my son, a tiny embedded app and a webapplication (using Rocket). So far I still like what Rust is trying to archieve – I’m not going to repeat that, other smart people have written in length about these topics. Instead I’ll try to give you my own take on some of the things I noticed.
Tooling & Ecosystem
Thus far, the tooling for Rust has blown me away (mind you – I’m not talking about IDE support, which is another story). Using the combination of rustup, cargo and crates.io is a productivity powerhouse that rivals the best out there. The toolchainmanagement of rustup makes cross compiling to just about any supported OS and architecture nearly trivial. What’s more is the breadth of the ecosystem. As hinted in the introduction the language scales from webapp to embedded development with ease and we have creates for nearly all use-cases out there. Getting an application to run on my little cortex m4 board was little more work than creating a web app using rocket.rs. I’ve yet to try out the WASM backend, but I’ve read many great things.
The ease that is provided by the integrated toolchain however has some drawbacks, which I feel don’t get enough coverage:
Crates.io
Pulling in crates via crates.io of yields a horror of subdependencies that make it specatcularly hard to figure out what you’ll get with that one crate you pulled in. In my humble opinion this is a serious security risk, since we will usually not have a closer look at all subdependencies. For example, take the sokoban clone I wrote earlier this year for my son. I added a single external dependency, namely “piston_window” to my cargo.toml file. The resulting cargo.lock file, withall dependencies resolved, has no fewer than 1425 lines, sporting 150(!) additional dependencies, that were pulled in by means of cargo. This means an enormous amount of code with questionable origin. The strong reliance an crates.io makes this service a neuralgic point in the ecosystem and it will probably the target of attacks as the popularity of the language grows. The most likely attackvector will probably be poisoned crates, i.e. crates that contain malicious code. If an attacker manages to compromise a popular crate such as serde the community will wake up in a world of pain. Note that this issue is actually only this high on my “OMG” list, because the underlying tooling is so good, that adding external code really is trivially easy.
Docs.rs
I think the idea of having a common repository for all documentation is nothing short of brilliant. The execution is – in case of Docs.rs – less than stellar. I absolutely loathe the automatically generated documentation there, as it is – IMHO – nearly useless for most crates, as there’s rarely any documentation on how a given crate should be used, instead we get a list of modules and traits, which is about it. Granted, there’s bad docs everywhere in the softwareworld, however I do have the feeling, that the Rust community somehow accepts the low standard set by many crates. This is a very sad state of affairs, as it makes it unnecessarily hard to use a lot of crates.
Rustc
Rustc is – in my opinion – the single most userfriendly compiler in existence. I’ve never encountered a tool that went to the same lengths to provide useful errormessages. That said: I’m not a fan of how oppioniated Rustc is with regard to codeformatting (…also I don’t like snake_case), but that is a matter of personal taste.
IDE Support
The folks who develop rust have made a couple of very smart choices regarding how a rust project is structured. That has led to a situation, where we can easily live without complex projectfiles, subprojects and the like. The fact that the few configuration files we need are human readable also help alot. All we need is cargo, and that does a tremendous job. Now, apart from that I’, not entirely happy with the IDE support we have from major vendors. I’ve used VSCode almost exclusively (but I’ve also had a look at Atom and IntelliJ), but so far I’m not exactly impressed with the featureset we have today.
- Debugging is a mess in most cases. Yes it works (well, or not), but the experience sucks because the debug support we get doesn’t get along with rusts binaries all that good, resulting in grossly mangled identifier names.
- Codecompletion has been vastly improved during the last two years, but there are still problems, especially with external crates (I’m looking at you, cortexm crate!). The fact that this issue seems to plague Atom as well as VSCode doesn’t exactly help either.
The language
Now, I wrote, that I’ll not mention all the features of rust, instead I’ll focus on a few interesting properties, that make the language worthwile in my business.
Mostly works when it compiles
I’ve read this statement only once or twice before, so I feel it should be mentioned: Due to the compiler being very strict about memorysafety it can be rather hard to get code past the compiler, especially at the beginning. However: Once it compiles one can be reasonably sure, that the program works (apart from logic errors). This is a very rare quality – my experience with other languages usually is:
- program feature
- start debugger
- see it crash
- fix memoryrelated bug
- rinse and repeat
Yes, this is a bit overexaggerated, however it does get the gist. Rust does a lot of this cycle at compile time automatically, so the cylce looks a bit different there and needs far fewer tests (be they manual or automatic).
Default to const
Most commonly used languages nowadays default variables and function parameters to being mutable. There are loads of talks that try to convince people to write “const correct” C++ code. In my daily work we take this very serious, however it is added work and sometimes people forget and reviewers don’t notice. Rust will default everything to const and the programmer has to manually mark data as being mutable. This is a subtle change, but it does get programmers to actually write more correct code.
Think different
Rust is a very interesting breed with respect to how we structure code. The lack of inheritance and strong focus on using generics represent as hard a learning curve as does the borrow-checker. A lot of the common design patterns don’t really make sense, especially given, that dynamic dispatch seems to be surrounded with an aura of bad-smell. This makes it a bit harder to wrap one’s head around the language as soon as we leave toy projects and start something larger.
Is it ready?
While this post seems to have a bit of a negative vibe to it I absolutely think that the embedded world should embrace Rust, as the ups far outweigh the downs. Especially if we look at the – still dominant – C, which makes it next to impossible to write safe code.
I’m still trying to figure out a way to get Rust into production in my dayjob, as I’d like to see how the experience is when multiple people work on the same codebase, and what kind of issues we’d face when integrating Rust/cargo with a CI build. I hope this will happen in 2020.
Image by Christopher Burns.