“Technology from the past comes to save the future from itself.” That’s how Graydon Hoare, the creator of Rust, describes what he wants to achieve.
That’s one of the key hallmarks of Rust: using technologies that are well-known to academia but rarely implemented in contemporary programming languages. Technologies that are old, reliable, and sometimes forgotten. But which, above all, work extremely well.
These technologies are used mainly for one thing: safety.
Sounds boring? It is not, if you ask the community. A whopping 87 percent of Rust developers love this language above all others, making it the most-loved language since 2016 according to this year’s StackOverflow developer survey.
You’d think that software developers are among the most innovative humans on this planet. Rust, however, is the exact opposite of the “move fast and break things” mantra. Nevertheless, Rust developers are almost guaranteed to learn concepts they’ve never heard about before.
From the novelty of systems programming for some developers over algebraic data types to Rust’s very own approach to memory safety: Every developer can find something new and incredibly useful to learn. And there are more reasons to fall in love with Rust.
More memory safety without garbage collection
One challenge of every programming language is managing a computer’s memory in a safe and efficient way. Python, for example, has a garbage collector that constantly looks out for no longer used memory and cleans it up while the program runs.
In other languages, like C and C++, the programmer must explicitly allocate and free memory as they go. Since all memory-related problems are therefore cleared before the program runs, this approach is much better for optimizing performance.
On the other hand, memory is yet another thing that developers need to think about all the time. This is one of the reasons why it takes much longer to write a program in C than in Python, even if it does the same thing at the end of the day.
Rust goes an alternative way: Memory is allocated through a system of ownership at compile time. It’s a neat hack to ensure that unused data is being cleaned without forcing the programmer to think about allocating and freeing memory all the time.
Basically, ownership is a collection of three rules:
- Each value in Rust has a variable called owner.
- There can only be one owner at a time.
- When the owner goes out of scope, the value will be dropped, thus freeing memory.
A simple example is assigning a vector in Rust:
In the second line, the vector [1, 2, 3] with the owner a is created. After that, b becomes the owner of the vector. Since the correct owner is called in the print statement, this program compiles and returns the expected result when executed:
On the other hand, you could try to call the vector with its previous owner, A, like so:
In this case, the compiler throws an error because a has already been dropped in the third line. There is a lot more depth to the subject, but this is the basic idea.
In comparison, Python would run through in the second case. Its garbage collector would drop A only after the last time that it is called, which is nice for the developer but not so nice in terms of memory space.
In C, things would be a bit more complicated: you would have to allocate memory space for a, then point it to the vector, then allocate more memory space for B, point B to A, and finally free the space taken up by A and B when you’re done.
In this sense, the approach of Rust to memory is a compromise between developing speed and performance. While it is not as dead-easy to write as Python, it’s not as clunky as C once you’ve understood the concept of ownership.
On the other hand, the efficiency is quite astounding: The developer team at Tilde, for example, managed to reduce their memory usage by 90 percent after rewriting some JavaHTTP pieces in Rust.
Static typing without getting ugly
It’s almost a religious war between fans of dynamic typing versus static typing. While it’s much easier to produce software in languages with dynamic typing, the code can become unmaintainable pretty quickly. This is one of the reasons why Python code can be quite hard to maintain, compared to C for example.
On the other hand, having to declare the type of each variable C-style can get rather annoying. If you’ve ever tried to use a [double] in a function that returns a [float] type in C, you know what I mean.
Rust goes a middle way: It’s a static type system, but it only requires the programmer to specify top-level types like function arguments and constants. Inside function bodies, Python-style type inference is allowed.
One particularly useful feature of Rust is that it has a None type as well. This allows you to handle exceptions at compile-time so that the program is guaranteed to run smoothly at the end-user. Consider this example, where we can get the full name of a person regardless of whether he has a middle name or not:
While versions of the None workaround exist in other languages, too, it showcases the ambition of Rust in a neat way: not making things too hard for writing while keeping the code as durable and maintainable as possible.
While Python is a general-purpose programming language, Rust is, like C, decidedly for systems programming. While Rust isn’t the ideal language if you’re making an application for your end-user, it is perfect for building pieces of software that provide services to other software.
A nifty approach to systems programming
As such, efficiency is at the core Rust. That’s best demonstrated by zero-cost abstractions, which interpret code while keeping memory usage to a minimum. As Bjarne Stroustrup, the inventor of C++, puts it: “What you don’t use, you don’t pay for. And further: What you do use, you couldn’t hand code any better.”
For example, consider adding all integer numbers up to 1,000 in Python:
This does 1,000 iterations and additions every time the code runs — and you can imagine how much that can slow the code down. In contrast, consider the same thing in Rust:
This compiles down to the constant 499500. Effectively, the memory usage has just been decreased by a factor of 1,000.
While these abstractions exist in C as well, Rust makes heavy use of them — in fact, one goal is to add as many zero-cost abstractions to the language as possible. In this sense, Rust is a bit like next-level C.
C has been around for more than 40 years, and Rust aims to do the same. Rust places such a high emphasis on backwards-compatibility that you can still run code in Rust 1.0 today. Likewise, if you write Rust code today, you should still be able to run it in twenty years. Rust won’t get rusty!
A small but incredible community
With its emphasis on safety and sustainability and all its nifty details speaking for it, it’s no wonder that Dropbox has rewritten a lot of its core structure in Rust. Mozilla, Rust’s first big sponsor, has written vital parts of Firefox in it. Microsoft deems C and C++ no longer safe for mission-critical software and is investing more and more in Rust.
And it’s not only big corporations — the love for Rust translates down to the individual programmer. Even though only five percent of StackOverflow’s survey respondents use Rust so far, these developers are extremely enthusiastic about the language.
And there are reasons for that. Not only are the language specification and the compiler very well thought through. There is rustup to install and manage toolchains. There’s Cargo, a command line tool that comes with each Rust installation and helps manage dependencies, run tests and generate documentation.
Beyond that, there are official and unofficial chats, subreddits, user’s forums, StackOverflow questions, and conferences all over the world. With a community that puts friendliness above everything, is there anything more to ask for?
The downside: the need to run before you can walk
The one thing that is discouraging about Rust is the high startup cost. While you would need one or two days to get productive in most languages, it’s more like one or two weeks in Rust.
This is due to the many new concepts that other languages don’t use, and the fact that there are typically a lot of errors at compile time. You need to handle all exceptions on day one, and can’t just write a scratch code that runs and add exceptions later, like you’d do in Python.
In addition, since Rust is still pretty new, not all libraries that you might want are there yet. Apart from the official documentation and various questions on StackOverflow, there are also not that many tutorials.
The good news is that once you’ve learned the concepts and got your program compiled, it runs through like a charm. Plus, it should still work in twenty years given the backwards-compatibility.
Given the sustainability of your code and the fact that Rust is backed by a number of large corporations, one or two weeks of up-front learning might well be worth it, despite the downsides.
The bottom line: hack without fear
Rust is more than safety. But it’s hard to deny that many of its core concepts aim at eliminating memory leaks and other safety issues. And in an age where software is everything, safety is a must.
There is probably a space for every upcoming language: Go is populating the space of Python and Java more and more, Julia is going after Python in Data Science, and Rust is growing in the realm of Python and C++. What makes Rust special is its incredible community, its innovative features, and the fact that it’s designed to work for decades to come.
There’s a lot more work to do, and only a fraction of that can and will be done in Rust. The new languages of today have a strong chance of sticking around for a while, even though other languages will emerge in the next few years, too. But if I had to place my chips on one language, Rust would be a safe bet.