Book Image

Rust Essentials - Second Edition

By : Ivo Balbaert
Book Image

Rust Essentials - Second Edition

By: Ivo Balbaert

Overview of this book

Rust is the new, open source, fast, and safe systems programming language for the 21st century, developed at Mozilla Research, and with a steadily growing community. It was created to solve the dilemma between high-level, slow code with minimal control over the system, and low-level, fast code with maximum system control. It is no longer necessary to learn C/C++ to develop resource intensive and low-level systems applications. This book will give you a head start to solve systems programming and application tasks with Rust. We start off with an argumentation of Rust's unique place in today's landscape of programming languages. You'll install Rust and learn how to work with its package manager Cargo. The various concepts are introduced step by step: variables, types, functions, and control structures to lay the groundwork. Then we explore more structured data such as strings, arrays, and enums, and you’ll see how pattern matching works. Throughout all this, we stress the unique ways of reasoning that the Rust compiler uses to produce safe code. Next we look at Rust's specific way of error handling, and the overall importance of traits in Rust code. The pillar of memory safety is treated in depth as we explore the various pointer kinds. Next, you’ll see how macros can simplify code generation, and how to compose bigger projects with modules and crates. Finally, you’ll discover how we can write safe concurrent code in Rust and interface with C programs, get a view of the Rust ecosystem, and explore the use of the standard library.
Table of Contents (13 chapters)

The advantages of Rust

Mozilla is a company known for its mission to develop tools for and drive the open standards web, most notably through its flagship browser Firefox. Every browser today, including Firefox, is written in C++, some 1,29,00,992 lines of code for Firefox, and 44,90,488 lines of code for Chrome. This makes them fast, but it is inherently unsafe because the memory manipulations allowed by C and C++ are not checked for validity. If the code is written without the utmost programming discipline on the part of the developers, program crashes, memory leaks, segmentation faults, buffer overflows, and null pointers can occur at program execution. Some of these can result in serious security vulnerabilities, all too familiar in existing browsers. Rust is designed from the ground up to avoid those kind of problems.

Compared to C or C++, on the other side of the programming language spectrum we have Haskell, which is widely known to be a very safe and reliable language, but with very little or no control at the level of memory allocation and other hardware resources. We can plot different languages along this control that is safety axis, and it seems that when a language is safer, like Java compared to C++, it loses low-level control. The inverse is also true; a language that gives more control over resources like C++ provides much less safety.

Rust is made to overcome this dilemma by providing:

  • High safety through its strong type system and smart compiler
  • Deep but safe control over low-level resources (as much as C or C++), so it runs close to the hardware

Its main website, http://www.rust-lang.org/en-US/, contains links to installation instructions, docs and the Rust community.

Rust lets you specify exactly how your values are laid out in memory and how that memory is managed; that's why it works well at both ends of the control and safety line. This is the unique selling point of Rust, it breaks the safety-control dichotomy that, before Rust, existed among programming languages. With Rust they can be achieved together without losing performance.

Rust can accomplish both these goals without a garbage collector, in contrast to most modern languages like Java, C#, Python, Ruby, Go, and the like. In fact Rust doesn't even have a garbage collector yet (though an optional garbage collector is being designed).

Rust is a compiled language: the strict safety rules are enforced by the compiler, so they do not cause runtime overhead. As a consequence, Rust can work with a very small runtime, so it can be used for real-time or embedded projects and it can easily integrate with other languages or projects.

Rust is meant for developers and projects where performance and low-level optimizations are important, but also where a safe and stable execution environment is needed. The robustness of the language is specifically suited for projects where that is important, leading to less pressure in the maintenance cycle. Moreover, Rust adds a lot of high-level functional programming techniques to the language, so that it feels at the same time like a low-level and a high-level language.

The trifecta of Rust - safe, fast, and concurrent

Rust is not a revolutionary language with new cutting-edge features, but it incorporates a lot of proven techniques from older languages, while massively improving upon the design of C++ in matters of safe programming.

The Rust developers designed Rust to be a general purpose and multi-paradigm language; like C++, it is an imperative, structured and object-oriented language. Besides that, it inherits a lot from functional languages on the one hand, while also incorporating advanced techniques for concurrent programming on the other hand.

The typing of variables is static (because Rust is compiled) and strong. However, unlike in Java or C++, the developer is not forced to indicate types for everything; the Rust compiler is able to infer types in many cases.

C and C++ applications are known to be haunted by problems that often lead to program crashes or memory leaks, and which are notoriously difficult to debug and solve. Think about dangling pointers, buffer overflows, null pointers, segmentation faults, data races, and so on. The Rust compiler (called rustc) is very intelligent and can detect all these problems while compiling your code, thereby guaranteeing memory safety during execution. This is done by the compiler, retaining complete control over memory layout, but without needing the runtime burden of garbage collection (see Chapter 6, Using Traits and OOP in Rust). Of course, safety also implies much less possibility for security breaches.

Rust compiles to native code like Go and Julia but, in contrast to the other two, Rust needs no runtime with garbage collection. In this respect, it also differs from Java and the languages that run on the JVM, like Scala and Clojure. Most other popular modern languages, like .NET with C# and F#, JavaScript, Python, Ruby, Dart, and so on, all need a virtual machine and garbage collection for their execution.

Rust provides several mechanisms for concurrency and parallelism. The Standard Library gives a model that works with threads to perform work in parallel, where each thread maps to an operating system thread. They do not share heap memory, but communicate data through channels and data races are eliminated by the type system (see Chapter 8, Organizing Code and Macros). If needed in your project, several crates provide an actor-model approach with lightweight threads. These mechanisms make it easy for programmers to leverage the power of the many CPU cores available on current and future computing platforms.

The rustc compiler is completely self-hosted, which means it is written in Rust and can compile itself by using a previous version. It uses the LLVM compiler framework as its backend (for more info, see http://en.wikipedia.org/wiki/LLVM), and produces natively executable code that runs blazingly fast, because it compiles to the same low-level code as C++ ( see some benchmarks at http://benchmarksgame.alioth.debian.org/u64q/rust.php).

Rust is designed to be as portable as C++ and to run on widely-used hardware and software platforms. At present, it runs on Linux, macOS X, Windows, FreeBSD, Android, and iOS. For a more complete overview of where Rust can run, see https://forge.rust-lang.org/platform-support.html.

Rust can call C code as simply and efficiently as calling C code from C itself, and, conversely C code can also call Rust code (see Chapter 9, Concurrency - Coding for Multicore Execution).

Rust developers are called rustaceans.

Other Rust characteristics that will be discussed, in more detail in the later chapters are as follows:

  • Variables are immutable by default (see Chapter 2, Using Variables and Types)
  • Enums (see Chapter 4, Structuring Data and Matching Patterns)
  • Pattern matching (see also Chapter 4, Structuring Data and Matching Patterns)
  • Generics (see Chapter 5, Higher Order Functions and Error-Handling)
  • Higher-order functions and closures (see also Chapter 5, Higher Order Functions and Error-Handling)
  • An interface system called traits (see Chapter 6, Using Traits and OOP in Rust)
  • A hygienic macro system (see Chapter 8, Organizing Code and Macros)
  • Zero-cost abstractions, which means that Rust has higher-language constructs, but these do not have an impact on performance

In conclusion, Rust gives you ultimate power over memory allocation, as well as removing many security and stability problems commonly associated with native languages.

Comparison with other languages

Dynamic languages such as Ruby or Python give you the initial speed of coding development, but the price is paid later in:

  • Writing more tests
  • Runtime crashes
  • Production outages

The Rust compiler forces you to get a lot of things right from the beginning at compile time, which is the least expensive place to identify and fix bugs.

Rust's object orientation is not as explicit or evolved as common object-oriented languages such as Java, C# or Python, as it doesn't have classes. Compared with Go, Rust gives you more control over memory and resources and so it lets you code on a lower level. Go also works with a garbage collector; it has no generics and no mechanism to prevent data races between its goroutines used in concurrency. Julia is focused on numerical computing performance, works with a JIT compiler, and also doesn't give you that low-level control as Rust does.