-- Leo's gemini proxy

-- Connecting to gemini.bunburya.eu:1965...

-- Connected

-- Sending request

-- Meta line: 20 text/gemini; lang=en-IE

Getting to know Rust


Lately I've been learning the Rust programming language and really enjoying it. Like most hobbyist programmers (I think), most of my programming experience has been in higher-level interpreted languages like Python. I have often been curious about learning a lower-level language like C, but the idea of having to manually manage memory seems tedious and error-prone.


In recent years, there are a number of languages which aim to be somewhat like C in that they are compiled, statically typed and performant, but with in-built memory management and some high-level abstractions available in the standard library. Go and Rust are probably the most talked about languages in that category and I've been considering learning one of them for a while.


I was originally leaning more towards Go, as I read a lot about how steep Rust's learning curve can be how and I thought it might be too difficult or take too much time to get my head around it. But particularly in the last year or so, Rust seems *so hyped* that I just had to see what all the fuss was about.


The Rust Programming Language


What I've been doing


I started by going through the excellent Rust Book, which gives a pretty good introduction to the language. There is a great tutorial I had bookmarked about how to build a basic terminal-based text editor in C, and I have also been going through that and trying to port the editor to Rust. That has been quite helpful in highlighting some of the key differences between the two languages.


The Rust Book

Build Your Own Text Editor (in C)


I also wrote a simple Linux command line utility that listens for certain UPower-related events (reporting changes to power devices) over D-Bus and prints those changes in an easily-parseable line-based format. I wanted an easy way to write scripts that react to power-related events on my laptop (like change in battery percentage or AC cable being plugged in) without having to continuously poll for changes or parse the more complex output of some other tools. Writing it was pretty painless as there are a few helpful Rust libraries out there, including one to interact with D-Bus.


`upmon`, my simple UPower monitoring CLI program

`zbus`, a Rust library for interfacing with D-Bus


I have also taken an interest in embedded programming. I bought a micro:bit v2 board and went through the Discovery Book, which gives a good introduction to embedded programming on that device using Rust. Having gone through the exercises in the book, I wrote a simple snake game which uses the micro:bit's LED matrix as a display and its buttons as controls, and then contributed a chapter to the Discovery Book on how to create such a game.


The micro:bit computer

The Discovery Book for Embedded Rust

Build a snake game for the micro:bit


My experience


Rust has made a really interesting change from Python, and although I haven't exactly made anything very complex in it, I haven't found the learning curve as steep or frustrating as I thought I might given what I had read about it. I think a lot of the steepness of that curve may come from having first learned how to do low-level things in C and then having to unlearn those habits. Coming from a high-level language it's not that bad--sure, it's more difficult because now you have to think about how the computer manages memory, but that is a challenge you would face in any event moving from a language like Python to one like C or C++. I won't deny I spent a lot of time in the early days fighting with the borrow checker, but I quickly gained an intuition for what is and isn't allowed, and how to structure my code to work with Rust's memory management. (And if all else fails, you can always `.clone()`.)


The good


One thing that struck me when I was making my command line utility is how simple it is to package Rust software. Cargo is a very powerful tool that can very easily pull together all your modules and dependencies and produce a single self-contained binary that you can share. It makes it easy to publish a project to crates.io, which is the Rust community's main package repository (though I haven't done this with `upmon` yet because I figure it probably makes more sense for libraries rather than binary packages). Cargo can be extended with third-party functionality that, for example, makes it easy to package for various Linux distributions--for example, I used the `cargo-aur` when packaging `upmon` for the Arch User Repository (under the name `upmon-bin`).


`cargo-aur`


There is, in general, Only One Way To Do It. You specify your project metadata in your Cargo.toml and Cargo handles building and (for the most part) packaging. No competing standards or toolchains.


The Rust documentation is also fantastic. Not only are the standard library and most popular third- party libraries well documented, there is also a "book" (ie, a tutorial or user guide) for just about every aspect of the language and a lot of the more popular libraries. These books are produced using the `mdBook` tool and so tend to have a pretty uniform look and feel. There is clearly a strong culture within the Rust community of writing not only good technical documentation, but also good user guides to introduce relevant libraries and concepts.


Rust leaning materials

More Rust learning materials

mdBook


The strictness of the compiler, and the helpfulness of its error messages, are another thing I really like about Rust. It's not quite true (never will be) that "if it compiles, it works", but Rust gets closer than any other language I've worked with. Not only does Rust's strong typing mean you avoid a wide range of type-related runtime errors, but the borrow system means you avoid a range of memory issues and race conditions, too. This does mean that in the beginning at least you will spend a lot of time fighting with the compiler, but its error messages are very helpful and will often explain exactly where you've gone wrong and even suggest fixes.


The bad (and ugly)


There are some aspects of Rust I am not crazy about though these are fairly minor things and may have more to do with my inexperience.


For one, a lot of Rust code relies heavily on smart pointers (like `Rc`, `Mutex`, `Box`, `RefCell`, etc). This can mean that data is nested within several layers of smart pointers which can make the code less clear.


Smart pointers


Similarly, a lot of libraries provide additional functionality through macros, which in my experience are more opaque and less easy to debug than regular Rust code. The errors you get when you misuse a macro may not be as helpful as when you pass bad arguments to a function, for example.


Macros


Of course, smart pointers and macros are powerful tools and can be really useful, but there can be trade-offs in terms of code clarity and compile-time protections that need to be weighed.


Finally, I find the error handling a bit clunky. You can end up with a lot of boilerplate code to check and unwrap `Result` values. Rust has a "try" operator (`?`) which can unwrap a `Result` or propagate the error up the call stack, but it is rather fragile as the error types must be the same. On the other hand, this does have the advantage in that it makes it pretty clear what errors might be raised by your code, and when.


Conclusion


There is a lot of hype about Rust right now. I can't speak to whether Rust will ultimately take its place alongside C and C++ in terms of popularity and significance. But I can say that as a hobbyist programmer, Rust is a fun and challenging language to learn and there are plenty of great resources out there to help you. Enjoy!



Getting to know Rust was published on 2024-02-16

Return to index

-- Response ended

-- Page fetched on Sat May 4 11:44:05 2024