Reading the article really struck me. Not only did I start with Rust about the same time, I too have been experimenting with Rust embedded for the first time recently, and had similar struggles.
However, I didn't attribute my difficulties to "features of the Rust language", but the specific way they were used -- particularly the design of svd2rust
's auto-generated crates and its interaction with embedded-hal
's traits.
I was trying to bring up an unknown-to-crates-io dev board, and get it to "blink hello world". There was a HAL crate for the microcontroller, at least, which made this seem not very daunting. I planned to follow The Discovery Book, tweaking as I went along, and sail smoothly through it.
As I had hoped, the first example compiled and booted on the board, but did nothing obvious (since the pins don't match, of course). But my attempt to make my own separate crate with similar-looking code turned into a sea of type errors and messy imports.
The example code was extremely readable, but was relying on a huge artifice. In addition to the example having an auxiliary file (which it took me embarrassingly long to figure out) the types full of generics and traits were in complex relationships not obvious at all from reading their cargo doc
s.
For example, I hit his specific complaint about all pins appearing to be different types, when I wanted to look at them as a collection. It took me over two hours to work out that:
- the GPIO fields of the
Peripherals
struct are members which implement RegisterBlock
and are themselves unique structs
- all of them have members which are unique types corresponding to pins, with generic subtypes
- the subtypes are defined in this crate, but they all implement the
Pin
trait despite their generic-ness
- through some other trait I couldn't quite figure out, you can get a
Writer
to the Pin
part
- that lets you access pin functions, whose return types are generic but change with based on what modes you set
- and in the end, that means and means you can
split()
them into a collection of the same type, which is the non-generic Pin
from embedded-hal
.
And I'm pretty sure I still didn't quite describe it correctly!
Even though I knew conceptually how embedded-hal
(and its ecosystem) was designed, and I was looking at example code for a very similar processor, it was the relationships between the dozens of items and traits across multiple crates I had a lot of trouble with. This "abstraction heirarchy" is something that per-item cargo doc
s without any top-level comments are not very helpful for, and I point the finger at svd2rust
for that. (EDIT: I don't mean to imply it's easy to fix, only that I think it was the cause.)
However, this was still Rust in the end. So once I figured it out, it Compiled And Ran Perfectly(tm). Now I could start on implementing peripherals (using the generics without worrying about the details nearly as much), and maybe even a full board crate someday.
I would certainly have never looked at another language. Most of the time, the precision and verbosity is exactly what I like about Rust, since most type abstractions don't get this deep.
I will not speculate on Zig the way he does on Rust's history at the bottom, but reading the Zig examples and their website does not make me feel like I could "be productive in Zig without an internet connection." Particularly that break :x res catch unreachable;
on their home page.
In conclusion, @Joe232 and other readers, that is definitely one guy's opinion.
EDIT 2: The crate I believe generated the base processor crate was fixed. No scalable vector graphics here!