All Articles

Why Developers Love Rust

Rust has been getting a lot of media attention recently. It has been voted the most loved language for five years running, and it grew in use on Github by 235% from 2018 to 2019. Large companies such as Mozilla, Apple, Amazon, Facebook, Google, Twitter, and Microsoft have began adopting it in their codebases. So, why do so many people love Rust?

Rust was built to solve many of the hassles associated with other popular languages. Let's look at a couple of examples:

Rust vs. Dynamic Languages

Developers coming from dynamically typed languages will find it hard to argue the benefits of static typing. Static type definitions are even being added to many popular dynamic languages, such as javascript's typescript, python's type hints, and ruby's rbs. Static languages are generally considered more "scalable" and better for larger codebases as the compiler does much of the work for you. Let's look at an example:

def silly(a)
  if a > 0
    puts 'hello'
  else
    print a + '3'
  end
end

The code above prints 'hello', right? Let's test it out:

$ silly(2)
=> "hello"

But, when you pass a negative number:

$ silly(-1)
=> TypeError (String can't be coerced into Integer)

You get a TypeError at runtime. A simple mistake like this can cause runtime errors that can sometimes be hard to debug without comprehensive test coverage. Since Rust is statically typed, all type errors will be caught at compile time, and this problem never occurs.

Static typing also results in compiled code that executes faster as the compiler knows the exact data types that are in use, and therefore can produce optimized machine code. Static types also serve as documentation.

The points in this section apply to pretty much all strongly typed languages. Let's look at some of the things Rust does differently than other statically typed languages.

No Nulls

Most languages have a concept of Null. Any value can either be what you expect, or nothing. If you accidentally miss a null check, you code can blow up. In Rust, Null is not even a concept, it does not exist! If x = "x", then x IS a string, and will always be a string.

If you really want nulls, you can use the Option enum. You can pattern match on that enum, and because Rust has exhaustive pattern matching, this code:

fn print_size(vector: Option<Vec<string>>) {
  match vector {
    Some(vector) => println!("{}", vector.len())
  }
}

Will not compile:

error[E0004]: non-exhaustive patterns: `None` not covered
--> src/main.rs:6:11
  |
6 |  match vector {
  |  ^^^^^^ pattern `None` not covered
  |
  = help: ensure that all possible cases are being handled, 
    possibly by adding wildcards or more match arms
  = note: the matched value is of type
    `std::option::Option<std::vec::Vec<std::string::String>>`

For more information about this error, try `rustc --explain E0004`.

To learn more, run the command again with --verbose.

In Rust, the code above would never make it to production, and clients would never experience the error because the compiler is so strict. Also note how detailed the error message is, telling you the exact location, issue, and potential solution to the error.

Rust vs. Statically Typed Languages

Rust does its best to get out of the developer's way when it comes to static typing. Rust has a very smart type inference engine. It looks not only at the type of the value expression during its initialization but also at how the variable is used afterwards to infer its type. However, Rust's use of type inference does not decrease its ability to provide detailed error messages at compile time. Here's an advanced example of type inference, straight from the docs.

fn main() {
  // Because of the annotation, the compiler knows that 
  // `elem` has type u8.
  let elem = 5u8;

  // Create an empty vector (a growable array).
  let mut vec = Vec::new();
  // At this point the compiler doesn't know the exact type of 
  // `vec`, it just knows that it's a vector of something (`Vec<_>`).

  // Insert `elem` in the vector.
  vec.push(elem);
  // Aha! Now the compiler knows that `vec` is 
  // a vector of `u8`s (`Vec<u8>`)

  println!("{:?}", vec);
}

No type annotation of variables was needed, the compiler is happy and so is the programmer!

Rust vs. Garbage Collected Languages

Garbage collection is an automatic memory management system that looks for unused variables and frees their memory. This can introduce performance issues at scale.

For example, Discord used Golang, a garbage collected language, for keeping track of which channels and messages a user read, which they call "Read States". They began experiencing latency and CPU spikes consistently every 2 minutes. This is because Go will force a garbage collection run every 2 minutes, scanning the entire LRU cache to determine which memory needed to be handled by GC.

Here is a before and after of them switching from Go, to Rust. Go is purple, Rust is blue.

Read the full post here: Why Discord is Switching from Go to Rust

Why is Rust so much better? Rust is blazingly fast and memory-efficient without needing a garbage collector, due to its ownership model.

// s is not valid here, it’s not yet declared
{
  let s = "hello"; // s is valid from this point forward
  // do stuff with s
}
// this scope is now over, s is no longer valid 
// and will be freed from memory

Thanks to Rust's ownership tracking, the lifetime of ALL memory allocated by a program is strictly tied to one (or several) function variables, which will ultimately go out of scope. This also allows Rust to determine when memory is no longer needed and can be cleaned up at compile time, resulting in efficient usage of memory and more performant memory access.

Skylight, an early adopter of Rust was able to reduce their memory usage from 5GB to 50MB by rewriting certain endpoints from Java to Rust.

Rust vs. Other Systems Programming Languages

Rust was built by Mozilla to be a the next step in the evolution of C or C++, two other systems programming languages. Rust gives you the low level control, while still providing features and conveniences that make it feel like a high-level languages. It gives you the technical power without allowing it to degrade from the developer experience.

Unlike something like Ruby, which disregards performance for developer experience, Rust provides as many zero-cost abstractions as possible; abstractions that are as performant as the equivalent hand-written code. Let's look at iterators for example:

let squares: Vec<_> = (0..10).map(|i| i * i).collect();

And the equivalent code in C:

int squares[10];
for (int i = 0; i < 10; ++i)
{
  squares[i] = i * i;
}

As you can see, Rust can be used create a vector containing the first ten square numbers much more concisely than C, but still highly performant.

Rust also has a second language hidden inside it that doesn’t enforce memory safety guarantees: it’s called unsafe Rust. Wrapping code with the unsafe block effectively tells the compiler to shut up, because you know what you are doing. Doing so gives you unsafe superpowers. For example, you can dereference a raw pointer:

let mut num = 5;

let r1 = &num as *const i32;
let r2 = &mut num as *mut i32;

unsafe {
  println!("r1 is: {}", *r1);
  println!("r2 is: {}", *r2);
}

If you can't do something in safe Rust, you can implement it yourself with unsafe, or, chances are, someone else has already done it, which brings me to my next point.

The Rust Ecosystem

Rust has become larger than just a language, it has a large ecosystem supporting it.

You can manage multiple installations and easily switch between stable, beta, and nightly compilers with rustup. It also makes cross compiling between multiple platforms simpler.

Rust also provides cargo, a tool for managing a Rust packages dependencies, running tests, generating documentation, compiling your package. Rust packages or "crates" created with cargo can be published to crates.io and made available for use by anyone. There are currently almost 50,000 available crates, and over 3.5 Billion downloads! Any library published to crates.io will have its documentation automatically built and published to docs.rs.

Unlike many languages, there is an official tool for formatting Rust code in rustfmt, as well as clippy, the linter that helps catch common mistakes and improve your code.

Rust has a very welcoming community. You can reach out through the discord chat, forum, subreddit, stackoverflow tag, slack channel, or gitter.

There are a ton of opensource projects created by the community. From web frameworks such as actix web, yew, and rocket, to Rust based text editors like remacs and xi editor. Even the language itself is opensource, and has 50,000 stars and over 3,000 contributors.

For a full list of resources, see Awesome Rust, a curated list of Rust code and resources.

Rust and WebAssembly

Another reason that people get so excited about Rust is how well it plays with WebAssembly. Webassembly is a binary instruction format that can run in most major browsers. It aims to execute at native speed by taking advantage of common hardware capabilities available on a wide range of platforms. Wasm can be run in the place of, or alongside traditional javascript, allowing developers to offload performance critical tasks from javascript, improving their application's performance without having to completely rewrite their existing codebase.

Rust can be compiled directly into WebAssembly and run in the browser with Cargo:

$ cargo build --target=wasm32-unknown-emscripten

This allows you to take advantage of all Rust's compile safety in the web. Since Rust lacks a runtime, generated .wasm files are very small because there is no extra bloat included like a garbage collector. Rust and WebAssembly integrates with existing javascript tooling. It supports ECMAScript modules and other tools such as npm packages and webpack.

There are some really cool Rust + Wasm projects out there. For example, Yew lets you create multi-threaded front-end web apps with Rust, in a way that feels almost like React.js.

For more information regarding Rust and WebAssembly, see the rustwasm book

Getting Started

Hopefully you understand why Rust is such a beloved language by developers. To get started with learning Rust, you should check out the Rust book. For other learning options and hands-on projects, click here