Why Rust
Greetings, fellow embedded enthusiasts! You’ve probably heard whispers about a new kid on the block - Rust. Now, you might be clutching your trusty C, thinking, “Is C dead? Should I start learning Rust? Why on earth should I rewrite my perfectly good C code in Rust?” These are all excellent questions, and fear not, we’re going to tackle each one in this article.
Welcome to another series of inpyjama blog posts. This series offers a practical introduction to Rust's core features. We'll prioritize code examples to illustrate how these features work. Occasionally, we'll bridge the gap by comparing Rust concepts to their counterparts in C.
Is C dead?
Absolutely not! Languages don’t just keel over and die, especially not when it’s the go-to language for nearly every embedded project and operating system out there. But is C perfect? Well, if you’ve ever found yourself wishing that C could be as easy to experiment with as Python, you’re not alone. Don’t get me wrong, I adore C. It’s my partner in crime for 90% of my daily tasks. It’s the ideal language for embedded systems, giving you the reins over memory and keeping bloatware at bay.
Should I start learning Rust?
Well, if you ask me, I'm a strong believer in continuous learning. I believe that whenever you get a job opportunity, you should grab it and learn as you go. However, there's another side to consider. How can you decide that Rust is not suitable for your project? If you want to make an educated decision about whether Rust is better than C for a project or not, you need to understand both languages. That means investing time in learning Rust so you can make an informed choice about the right tool for the job.
What about my legacy code?
So, you might be wondering, 'Should I rewrite my legacy code in Rust to integrate with my new project?' Well, I'd say that's a bit crazy! Rewriting all that C code would be a massive undertaking. Luckily, Rust understands this dilemma and provides something called a Foreign Function Interface (FFI). This lets Rust code work smoothly with functions written in other languages. We'll dive into the details of FFI in future articles.
Enter Rust
So, what’s the deal with Rust? Imagine a language that’s as speedy and compact as C and C++, but also ensures memory safety.
I like to think of Rust as a compelling combination of C and Python. It offers the lean, low-level efficiency of C while ensuring the memory safety and ease of use found in Python. While I could delve deeply into Rust's memory safety mechanisms, that would make this article far too lengthy. Instead, let's explore some of the lesser-discussed aspects of Rust that make it so appealing, qualities often overshadowed by its renowned safety benefits. We'll cover memory safety in depth throughout this series.
Let's shift the spotlight away from Rust's memory safety for a moment and talk about some of its underrated features.
The build system
While parts of the C++ community have adopted tools like Blaze and CMake, majority of the C community still rely on Makefiles. Honestly, Makefiles feel like the assembly language of build systems – they work, but they're outdated and there are better ways. I even wrote a whole article series on why I avoid writing Makefiles directly, preferring to use CMake to generate them!
One of Rust's greatest strengths is its built-in build system and package manager, Cargo. It's fantastic! The tight integration with the compiler means minimal setup to get your project rolling. Cargo also handles dependencies like a champ, allowing you to specify precise versions. This kind of dependency management is a serious pain in C. I know some might argue that Makefiles are still essential for massive projects like Linux, but even there, it's not just Makefiles doing the work – there's a whole suite of complex tools involved. Google 'GNU auto hell' if you don't believe me!
Rust's central package repository, crates.io (think of it like Rust's version of PyPI), is another gem. Cargo lets you easily fetch packages at specific versions. If you're eager to dive into Cargo, here is the Cargo Book, but we'll also explore it in detail in a future article.
Better Module system
The second thing I really like about Rust is its module system. It reminds me a lot of Python's import system, which is a huge plus. In C, we all know the drill: for dependencies, you use the #include
preprocessor macro with the header file's name.
But, as projects get bigger and code reviews aren't super meticulous, a major problem sneaks in – what I like to call 'noodled headers'. Over time, instead of directly including the headers that define the necessary interfaces, developers sometimes include other headers that happen to indirectly include those needed ones. This chain reaction continues, and before you know it, every header includes every other header. Sounds convenient, but it's a nightmare! Change one header, try to remove one, and suddenly things break in unexpected places. And if that header contained a macro you relied on? Good luck getting the compiler to pinpoint that error.
Rust's module system is the antidote. It's precise and to the point. Want to use an interface? You have to explicitly bring it into scope. This clarity is a lifesaver as your project grows, giving you a crystal-clear list of dependencies for each Rust file.
Much Verbose Compiler
If you've ever spent hours deciphering those cryptic GCC errors, hunting down a rogue semicolon or a misbehaving macro expansion, you're a true C programmer!
Rust really shines in this area. One of the first things you'll notice on your Rust journey is how incredibly helpful the compiler is. It won't just tell you what's wrong – it'll often drop hints on how to fix it! The error messages are detailed and sometimes even include links to the Rust standard library for deeper understanding. A huge advantage is that, unlike C, there's no such thing as compiler-specific behavior(well there is only one compiler as of today) or undefined behavior. Everything in Rust is clearly defined and documented.
What next
Now, you might be thinking, 'This guy must really hate C!' Honestly, that's not true at all. Yes, I highlighted some of C's drawbacks and how Rust tackles them, but that doesn't mean Rust is perfect. There are downsides, and you'll definitely discover them on this journey. Prepare for the occasional keyboard breaking frustration with Rust's borrow checker! But we'll save those lessons for later articles. Ultimately, we'll weigh the pros and cons of C and Rust, exploring where Rust truly excels, and help you decide if it's the right choice for your next project. See you then
Discussion