A brief history of Rust
Rust is a general-purpose, multi-paradigm, compiled, strictly statically typed programming language designed for memory safety and performance. Rust’s development began in 2006 as a personal project of Graydon Hoare, while he was working at Mozilla Research. In 2009, Mozilla began sponsoring the project and in 2010 they officially announced it.
Rust grew in popularity and is in the top 20 programming languages according to the TIOBE index.
Since 2021, Rust has been stewarded by the Rust Foundation, a non-profit organization that nurtures the Rust ecosystem and provides assistance to the group of maintainers in charge of overseeing and advancing the project.
How is Rust different from other programming languages?
Rust is memory-safe, thread-safe, fast, and memory-efficient, with no runtime or garbage collector. The Rust compiler generates with LLVM-Tools platform independent LLVM-IR code (IR stands for intermediate representation) and then native machine code for the target platform.
A short technical dive
Ownership is a distinct feature that enables Rust to make memory safety guarantees without the need for a garbage collector. Memory management is governed by a set of rules that the compiler checks:
- Each value in Rust has exactly one owner
- When the owner goes out of scope, the value will be dropped
The program will not compile if any of the rules are broken.
Borrowing, or the act of creating a reference, also has strict rules that help prevent data races:
- A borrow must last for a scope no greater than that of the owner
- You can have one or more immutable references to a resource OR exactly one mutable reference
Using ownership, borrowing and type checking helps detect concurrency errors at compile time, instead of runtime. As a result, developers can fix the code while working on it and avoid introducing potential bugs in production.
Rust implements threads in a 1:1 model, meaning that a program uses 1 operating system thread for 1 language thread. Threads can communicate with each other using directional channels. The Rust standard library also provides smart pointer types, Mutex<T> and Arc<T>, for safe use in concurrent contexts.
Rust’s other strengths include excellent documentation, helpful compiler error messages, and a friendly community.
Here is a sample of the borrowing concept from the official Rust page:
// This function takes ownership of a box and destroys it
fn eat_box_i32(boxed_i32: Box<i32>) {
println!("Destroying box that contains {}", boxed_i32);
}
// This function borrows an i32
fn borrow_i32(borrowed_i32: &i32) {
println!("This int is: {}", borrowed_i32);
}
fn main() {
// Create a boxed i32, and a stacked i32
let boxed_i32 = Box::new(5_i32);
let stacked_i32 = 6_i32;
// Borrow the contents of the box. Ownership is not taken,
// so the contents can be borrowed again.
borrow_i32(&boxed_i32);
borrow_i32(&stacked_i32);
{
// Take a reference to the data contained inside the box
let _ref_to_i32: &i32 = &boxed_i32;
// Error!
// Can't destroy `boxed_i32` while the inner value is borrowed later in scope.
eat_box_i32(boxed_i32);
// FIXME ^ Comment out this line
// Attempt to borrow `_ref_to_i32` after inner value is destroyed
borrow_i32(_ref_to_i32);
// `_ref_to_i32` goes out of scope and is no longer borrowed.
}
// `boxed_i32` can now give up ownership to `eat_box` and be destroyed
eat_box_i32(boxed_i32);
}
You can try it directly on the page:
And you will get that:
The error combined with a good explanation (rustc ist the Rust-Compiler).
And now fixed:
// This function takes ownership of a box and destroys it
fn eat_box_i32(boxed_i32: Box<i32>) {
println!("Destroying box that contains {}", boxed_i32);
}
// This function borrows an i32
fn borrow_i32(borrowed_i32: &i32) {
println!("This int is: {}", borrowed_i32);
}
fn main() {
// Create a boxed i32, and a stacked i32
let boxed_i32 = Box::new(5_i32);
let stacked_i32 = 6_i32;
// Borrow the contents of the box. Ownership is not taken,
// so the contents can be borrowed again.
borrow_i32(&boxed_i32);
borrow_i32(&stacked_i32);
{
// Take a reference to the data contained inside the box
let _ref_to_i32: &i32 = &boxed_i32;
// Error!
// Can't destroy `boxed_i32` while the inner value is borrowed later in scope.
// eat_box_i32(boxed_i32);
// FIXME ^ Comment out this line
// Attempt to borrow `_ref_to_i32` after inner value is destroyed
borrow_i32(_ref_to_i32);
// `_ref_to_i32` goes out of scope and is no longer borrowed.
}
// `boxed_i32` can now give up ownership to `eat_box` and be destroyed
eat_box_i32(boxed_i32);
}
With the result:
What are the main tools for Rust?
Cargo is the primary build system and package manager for Rust. With Cargo, developers can:
- Build, run, and test the code
- Download the libraries that the code depends on and build those libraries – in Rust a library is named “crate”
- Customize a build through release profiles
- Publish libraries on crates.io
- Install binaries from crates.io
- Manage large projects with a feature called workspaces
- Introduce conventions to make working with Rust packages easier
Two other useful tools are rustfmt and clippy (all tools in the the “realm” are controlled by cargo, such as “cargo clippy”, “cargo rustfmt”). rustfmt helps format code according to guidelines. clippy is used for catching common mistakes and improving the Rust code (static code analysis/linting).
crates.io is a large collection of high-quality open-source libraries. There are 100,000+ crates available that provide alternatives to libraries written in other programming languages.
What kind of software can be built with Rust?
Rust is general-purpose, but its unique features make it suitable for system programs that are in direct control of hardware resources, command line tools, WebAssembly, network services, or embedded development. In the meantime there are some crates for REST API, so Rust has the potential to be a “first citizen” for backend development in a cloud native, containerized environment due to its small “footprint”.
Rust was used in several noteworthy software, including:
- Servo, a parallel browser engine
- Redox OS, a Unix-like operating system
- Firefox’s CSS engine – Stylo
- Dropbox’s sync engine
- Cloudflare Oxy, a next-generation proxy framework
- Discord’s “Read States” service
Is Rust difficult to adopt?
Rust can appear to have a steep learning curve, but developers are very fond of it. In the beginning, things can get a bit frustrating because the compiler gives lots of error messages. Yet, it always gives good suggestions for a solution and, in the end, these are errors that come up in other programming languages at runtime.
Big names in tech like Amazon, Microsoft, Alphabet, Cloudflare, or Meta are already using it.
Linux Kernel included support for Rust in its 6.1 release, at the end of 2022.
Android adopted Rust in 2019 to fix the vast majority of the security issues. At the time, Android version 10 had 223 known memory safety bugs. The current Android version has 85 known memory safety issues, a 61.88% decrease. In December 2022, Google declared they had not seen a single memory safety vulnerability in Android’s Rust code, which made up approximately 21% of all new code.
A growing number of companies are looking at Rust as a replacement or companion for C/C++, in order to avoid security issues caused by memory safety bugs. Rust eliminates classes of vulnerabilities without affecting performance. For big projects, we do, however, recommend a strangler fig approach—introduce new functionality gradually, rather than a complete rewrite of the code base.
In 2019, Microsoft said that over the last few years, around 70% of all patches were fixes for memory safety bugs. Google reported in 2020 that 70% of all serious security bugs in the Chrome codebase are memory management and safety bugs. 60% of the Android codebase issues are represented by memory safety bugs and errors in handling memory in native programming languages.
The National Security Agency recommends the use of a memory-safe language when possible: “Using a memory safe language can help prevent programmers from introducing certain types of memory-related issues. Memory is managed automatically as part of the computer language; it does not rely on the programmer adding code to implement memory protections. The language institutes automatic protections using a combination of compile time and runtime checks. These inherent language features protect theprogrammer from introducing memory management mistakes unintentionally.”
The United States Department of Commerce’s National Institute of Standards and Technology (NIST) added Rust to its list of “Safer Languages” in March 2023.
Conclusion
Rust has such a touch – it’s what I’ve always expected.
Want to learn more about Rust?
Check out TechRadar by Devoteam 2023 to see what our experts say about it in the market.