Share: Facebook icon - Twitter icon - LinkedIn icon

What I love about Rust

Published Mon Oct 31 2022

Tags: programming rust


I have really fallen in love with Rust this year! It has many positive features, like compiling to almost any platform, nice syntax and more. In this article I will show you some of these features, tell you about them, and maybe inspire you to look into learning Rust yourself! If you disagree about something being awesome, then that is okay too, as the article is based upon my personal opinion.

Easy installation - rustup

Installing the basic tools (compiler, build system etc.) is very easy by using rustup. rustup is also used to update the tools, install other components (formatter, language server etc.), install unstable/nightly versions of the tools, install other Rust versions and so on. It is also used to set the default compiler/tool versions etc. This means that an official language tool handles quite a lot for us out of the box, and that we don't need to find other tools to do these tasks. If you have used other ecosystems like Node.JS, Java etc., you will know that you will often need several different (often unofficial) tools to handle multiple versions (e.g, nvm for Node.JS), installing official tooling etc. This simplicity in the Rust ecosystem makes it really easy to get started, and also doing lots of common tasks in a standard way. In other ecosystems you will probably do more research to do these things than you would have to do with Rust.

Build system - Cargo

Rust comes with a powerful build system for your projects, which is also used to install programs directly from source (e.g, git or crates.io). This build system handles building/compiling, fetching dependencies, running tests (including having a built in test runner!), and more! The way it handles dependencies is very modern, with each project having a Cargo.toml file specifying dependencies and their versions. If you have used older build systems like CMake, automake etc., you will be pleased that you don't need to handle dependencies yourself and that you can have multiple versions of them on the same system. If you are coding in the Java ecosystem, you will probably be happy that there is a great build system out of the box, instead of having to research which one to use (for JVM languages you have Maven, Gradle, Ant etc., no standard one). Printing a dependency graph, which requires a plugin on the JVM with Maven, can be done out of the box with cargo tree.

The test runner has one really neat feature; code snippets in documentation comments are run when executing tests! This means that you will not have stale code in your documentation that fails to compile.

Cargo makes it easy to add extensions. Simply make a program called cargo-name (where name is the name of your extension), put it in your path, and you can use it like it was a built in cargo command. There are some great ones available, including cargo-generate (to use project templates) and cargo-udeps (to find unused dependencies).

There is also an official code analyzer that integrates well with Cargo called Clippy! Very useful to catch possible mistakes, bugs, possible performance issues etc.

Hopefully I've now teased some of the features I really love about Cargo! Covering everything is a bit out of scope for a small article like this :)

Compiles to almost any platform!

Rust compiles to many different computers, micro controllers, game consoles and more. This is all thanks to the compiler utilizing LLVM for generating machine code. LLVM supports generating machine code for many different computer architectures, and thanks to it we can describe Rust targets. The targets describe the architecture, operating system and so on an executable runs on. Many are built into Rust, and we can also create our own. This has lead to support for many different architectures, which off course includes many micro controllers and computers. Some interesting ones include Linux on Motorola 68k processors (hopefully we can hack together AmigaOS classic and 4.1 variants in the future!), GameBoy Advance, and older 32 bit Windows versions (including Windows 95!).

Compiler guides you! - Useful compiler messages

The Rust compiler have, in my view, really useful compiler messages! I often feel like they guide you to the solution you might want (within reason off course). I could construct an example here, but I feel like the Rust book have a great early tutorial that shows you this in action!

Better enums

You are probably used to enums to do simple enumerations in many languages. In Java, Kotlin and many similar languages they can also contain some data, though this data can not vary for the same enum value (the definition of an enum value has to call the constructor directly). Rust enums are way more powerful, and in my view operate more in a way as a sort of category. Let us see some code with comments:

// very simple standard enum
enum Color {
      Red,
      Blue,
      Green
  }


// a more advanced where some values may contain data
enum HttpRequest {
    Get,
    Post { data: String },
    Put { data: String },
    Custom { code: i32, data: String },
    Unknown
}

In the last variant we see that the Post, Put and Custom variants contain data. This data can vary based upon user inputs, calculated values, etc. It might also be unique for each enum value (e.g, two Post's may have different data). Each enum value is more like an internal struct than a hardcoded value. We also see that the enum values can vary with their number of fields. Enums are covered in great detail in the official documentation.

These powerful enums relate to our next topic; Rust's awesome pattern matching!

Awesome pattern matching

We can destructure, check for matches etc.:

// destructure a Point structure that contains x, y and z variables
let Point { x, y, z} = my_point;

// match a specific enum and use the data field
if let HttpRequest::Post { data } = my_request {
    // .. do something with the post request data ...
}

I have an article on pattern matching in Rust that might be of interest, which goes more in-depth on the syntax. It also have links for further reading.

Error handling that makes sense

One thing I think is really great in Rust is that we don't have big bloaty exceptions. Rust have two types of error scenarios: recoverable and non-recoverable. Non-recoverable errors are done by stopping the program (i.e, panic), and possibly giving a stack trace (depending on settings). This type of error is well documented, and as it is non-recoverable we can't handle it that much. Recoverable errors on the other hand we can handle!

Recoverable errors are handled with the Result type, which you can think of as a generic enum. It has two possible values; Ok and Err (both which can contain data). This means that we can handle Rust errors like other pattern matching scenarios!

match possible_error {
    Ok(data) => println!("Yay! Data: {}", data),
    Err(err) => println!("error!")
}

There are also many methods on Result like unwrap (panic if error, or else give us the result), expect (to fail with a custom panic message), and unwrapordefault (to get a default value if error). The documentation for std::result covers this in great detail for those of you who are curious :)

Closures and functional programming features

Like many other modern languages, Rust provides functional programming features. Closures, similar to lambdas in other languages, act as anonymous functions. You can use higher order constructs (i.e, functions that take functions as input and/or return functions) to iterate, like map, filter, reduce etc. In Rust, this concept is called iterators. It looks something like this:

let result: Vec<i32> = my_list.iter().map(|val| val * 2).collect();

One of the best parts is that these constructs compile to the same code as regular loops, and there is no overhead added! It is therefore called one of Rusts zero-cost abstractions!

The ownership model

Rust have a simple, but effective way to manage memory. Each value has only one owner, and assigning the content to a new variable moves it to that new variable. Other places can borrow it, but two places cannot own the same value (there are ways to work around this with reference counters though). Having these "restriction" makes it possible for the compiler to handle the memory more or less for us (you don't really do manual allocation and deallocation yourself like you would in C). Owner going out of scope, means that the value will be dropped. This system of ownership is probably one of Rusts most unique features, and you can read more about it in the Rust book.

Simplified "object orientation" - No heavy OOP like in Java or C++

I have to admit, I'm not a big fan of the heavy object orientation constructs in Java and similar languages. Interfaces, abstract classes etc. are okay concepts, but not necessarily all the design patterns and solutions built around them. They solve specific problems, and can work if they are used to share common languages between developers… but they seem so far away from how computers really work. In some code bases, especially enterprise ones, they are often overused (some people seem to have a competition on who can cram the most object oriented design patterns into a code base). Look at the satirical FizzBuzz Enterprise Edition for an example of what I'm talking about.

Here is the feeling I get very often when reading Java code bases:

Object oriented programming meme

(stolen meme, probably from /g on 4chan)

Rust on the other hand, are more like C in this regard. Structures, enums etc. are our primary building blocks. We can implement traits (almost like interfaces), but traits can not contain implementation logic (only the implementation block for that trait in a given struct can). Solutions in Rust, at least from what I've seen, also end up being more simple in a lot of cases, with lists of indices instead of linked lists and so on. Many code bases also use enums to solve problems in clever ways. The official documentation (or Rust book if you will) covers object orientation in Rust in a far better way than I could, so I suggest looking into it if you want to read more :)

NOTE! I'm not hating on design patterns in general. I think they can be a good to convey concepts and discuss solutions to problems. What I'm hating on is their overuse, and cramming them into all sorts of places.

NOT focused on selling a specific editor/IDE - language server implemented as an official core component

rust-analyzer, the language server for Rust, is an official Rust project. The people behind Rust does NOT do favoritism with any IDE, or try to sell you one (looking at you Kotlin!!!). This means that you can use any editor you like. For some languages, like Kotlin, most people end up using the official IDE, and the language servers end up having limited interest and contributions. Rust is different, and therefore everything works great in Emacs! Though I would recommend using rustic instead of rust-mode (the latter is linked to on the official rust-lang website), as it builds on top of rust-mode and provides more features (e.g, automatic LSP configuration, some Cargo popups etc.).

Want to learn Rust now? - Recommended resources

NOTE! The book links are Amazon Affiliate links where I make a commission on qualified purchases.

I think the best way to get started with Rust is to read The Rust Programming Language book, and do Rustlings exercises while reading it (interactive exercises!). The next steps will probably be to hack away at your own projects, open source code etc. If you still find Rust interesting, I can recommend Rust Brain Teasers. It is in the style of books like Java Puzzlers, where you are presented with edge cases and weird behavior and should guess what happens (i.e, if it compiles, what it prints etc.).

For those of you who may have read this article, and are familiar with Rust, you might want to go deeper. Maybe you want to know more about how everything works under the hood? More advanced concurrency and parallelism? Unsafe code? Other efficiency tricks, and things needed for embedded Rust? Then I can recommend Rust for Rustaceans. The author, Jon Gjengset, also have a YouTube channel where he goes through intermediate Rust concepts (maybe there is some newbie friendly as well?).




Other posts that might interest you: