Finding Time for Rust: 7 Simple Steps to Learn Rust

Rust appears to be gaining steam as a solid language to solve complex and challenging problems in embedded systems; it provides powerful safety guarantees, is built for speed, and has mechanisms to make programs safe from memory guarantees while remaining fast. 

7 Simple Steps to Finally Find Time to Learn Embedded Rust

POZNAN, POL - APR 15, 2021: Laptop computer displaying logo of Rust, a multi-paradigm programming language designed for performance and safety, especially safe concurrency

“I don’t have time to learn X! I’ve got so much on my plate already!”

That seems to be the standard excuse that we tell ourselves when faced with the prospect of taking time out of our admittedly intense regular schedules to learn or incorporate something new-whether it’s a new development process or programming language.

As experienced programmers, we’ve gone through this process multiple times: 

  1. There is remarkable hype/noise/hope around the next shiny object.
  2. We put in the time and effort to see how it would improve our development experience or solve a particular pain point, and then it doesn’t live up to its promise.
  3. We scuttle that distraction, gradually building skepticism about the benefits of the next new tool/method/pattern/language/sdk.

There have been notable exceptions where the next shiny thing ended up being a net positive, bringing about far more productivity and flexibility to our embedded systems world. I’ve experienced this with things like FreeRTOS, Docker, and-increasinglyRust.

Right, what’s all this about Rust?

Rust is a powerful, relatively new, programming language that was designed to provide safer memory management than C or C++, yet retain most of the speed and “close to the metal” properties that we require when developing for embedded systems. It also has constructs that make concurrent and parallel programming less error prone.

options-bg-1

Although you might be more familiar with Rust’s use in storage services, web services, and browsers,  you’ll also find it in production hardware. There is growing momentum to transition to memory-safe programming languages (see the RFC to get Rust into the Linux Kernel, and the NSA’s recent communique). In addition, there’s been considerable effort to get it to run well on embedded systems, evidenced by a growing list of board support packages, books, examples, and other training materials.

That said, Rust has some particularities that make it tough to dive right in. It introduces a complex syntax, and concepts like ownerships, traits and lifetimes. It’s no surprise that there are over 50 million results for “why is Rust hard to learn” on Google. On the other hand, Rust provides tools and constructs to solve challenging and complex programming problems, making it a compelling language to learn. Learning Rust for Embedded Systems has a ton of great resources for why and how to learn Rust for embedded.

So how does one make time to learn this new language and incorporate it into projects that-at least on paper-would suffer fewer crashes and vulnerabilities?

As with anything, it takes time to learn a new language, understand what it can do for you, build fluency, evaluate how you would incorporate it in an existing project, or use it for a new one.

The total amount of time is about the same. Whether you’re intense and spending several hours per day for a month, or simply spending a few minutes a day for a year. While it would be nice to have a whole month carved out for this process, the majority of us don’t have this luxury and must squeeze our learning into short chunks. I’ve adopted the second style for my learning journey, and have shared some tips that have helped me.

Finding time to learn Rust…

1) Tiny bites

The key is “tiny bites at a time”. Find 10-15 minutes, perhaps after lunch, or first thing in the morning-but certainly at a fixed time daily-to dedicate to your task.

2) Read short examples

The very first thing I did when I heard about Rust-and what I typically do with any language-was to look at some very short examples. What’s the syntax like? How many steps does it take to solve a trivial problem? As an embedded engineer, my foremost concerns are the easy ones: can I blink an LED or detect a button press with the same ease as I can in C? Can I read and write memory mapped registers? A language that does not allow access to low-level peripherals is useless for my purposes, so I was quite relieved to see that Rust offers packages (called crates) that do this very thing. It’s not as straightforward as assigning data to a pointer, but I was satisfied (despite readers’ comments) with this side-by-side comparison of porting a GPIO driver to Rust

I also spent a few days reading Rust by Example, to see what features the language offered to solve the types of problems I deal with in embedded development. It’s a great resource that fits into the “bite-sized” approach because most sections are relatively brief, and can be read within 15 minutes. In addition, check out some of the various excellent YouTube channels dedicated to Rust, like Let’s Get Rusty, Jon Gjengset’s channel, or the Rust team’s curated channel.

3) Find an online simulator

Ultimately, to get a proper feel for what it would be like to program in Rust, you’d want to install the tools (e.g. compiler and package management) on your computer. However, since I wasn’t quite yet convinced, I didn’t want to invest any time (or disk space) to Rust quite yet. Instead, I started looking for online compilers and interpreters that could be run from a web-browser. I settled on the Rust Playground for experimenting and trying out some small examples. As an embedded developer, I often examine the resultant assembly code to be sure of what the machine is actually doing, and have come to find the Compiler Explorer invaluable for that purpose.

4) Try out small examples

Start trying out the concepts from the examples above by writing small programs using the online simulator. Experiment with variables, types, bindings, scope, shadowing; you might find yourself delighted with some niceties that you wished C had. Move on to flow control, iteration, functions, and high-order functions. Test aggregate types like tuples and structs.

Then comes the screeching halt: trying to implement a linked list with Rust. It’s surprisingly difficult given Rust’s perspective on object ownership, borrowing, and mutability. I went off in the weeds trying to implement what I think is an important abstract data type, before the realization hit me: Rust natively supports arrays, slices, vectors, and has a crate that implements queues. Why reinvent the wheel? See “too many linked lists” if you insist on solving a redundant issue.

Going further, try out some more complex examples that take advantage of the strengths of Rust. How does one write, say, a single producer-consumer program? Well, Rust provides threads to divvy up the work, channels to communicate between them, async/await for task concurrency-especially for i/o bound workloads-and can lock stdout to prevent interleaving of text messages. Bonus (for me): Rust can lock stdout to prevent interleaving of text messages; how many times have your debug messages stomped on each other? These are things hard to get right in C (or even C++), so having them be part of the language means less time spent debugging these patterns.

5) Looks like it’s time to install the thing

Unsurprisingly, installing the Rust development system takes little time since there are packages for pretty much every operating system. Alternatively, you could install it as part of an already existing Docker image (not to go off on a tangent, but Docker is a great containerization tool for embedded development).

Unlike C or C++, developing with Rust means you’ve got a native build system, updater, and package management that makes life a lot easier. It took all of 5 minutes to write my first complete (albeit tiny) Rust program and execute it locally.

If you’re like me, you have a collection of small utilities written in C. For instance, I have a much-simplified replacement to /usr/bin/find because I could never remember the more complex syntax. It’s straightforward path iterating and pattern matching, and hews to the Unix philosophy on simplicity. Another “shortcut” simply converts decimal arguments to their hex equivalent, and vice versa. Another sums all its arguments and so on. Why? Well, pipe some hex addresses from a piece of code, sum them, and find a few offsets in decimal. Beats using a GUI calculator and copy-pasting each thing manually. I found that writing a Rust version for each one gave me more motivation to keep at it because I was solving little problems that were personally meaningful to me. Often this may be the best way to learn.

6) Doing Embedded Rust

Now it’s time to turn our attention to the end-goal of all this effort and practice: get Rust working on an embedded system. The first thing to do is read up on Embedded Rust, and while doing so, find a platform you like that has good board support (for Rust). There are resources for STM32, NRF, NXP, AVR, and the Raspberry Pi Pico (among others), in different states of maturity, so you’re spoiled for choice. Alternatively, you can use QEMU. This allows you to emulate the hardware to run your programs on while you figure out the development platform, the tools, and how Rust can make use of various hardware resources. Then, proceed to rewrite small test utilities-or even an entire program-using the skills you developed during the earlier sections.

7) Make time for learning in your career

Far too many engineering companies expect every hour to be spent actively working on projects or billing for clients, with no time allocated to learning or self-improvement. There are some companies, like Dojo Five, that have found it beneficial to block out a few hours every week for engineering to spend time on education and process improvements. “Always learning” is one of our company values and “Dojo” translates to “place of the way”-representing an environment for immersive learning. By incorporating new ideas or learning a new skill, engineers can improve their craft.

In conclusion

Rust appears to be gaining steam as a solid language to solve complex and challenging problems in embedded systems; it provides powerful safety guarantees, is built for speed, and has mechanisms to make programs safe from memory guarantees while remaining fast. 

A colleague mentioned that every time he walks away from Rust for a while it changes and it’s hard to get back into it, which appears to be an ongoing challenge that the Rust-curious run into. If you can continue to schedule time for tiny bites, build your skills through examples, and work these skills into your day-to-day work, you can finally learn and feel the confidence to apply Rust to many embedded development challenges.

DojoFive brings modern tools, techniques, and best practices from the web and mobile development environments, paired with leading-edge innovations in firmware to our customers to help them build successful products and successful clients. We have talented engineers on hand ready to help you with all aspects of your EmbedOps journey. Bring your interesting problems that need solving – we are always happy to help out. You can reach out at any time on LinkedIn or through email!