Agile devops & continuous delivery
Rust
Definition of Rust
Rust is a compiled programming language with a focus on memory safety and concurrency/thread safety, plus performance. It is a multi-purpose and multi-paradigm language. Instead of providing ever-higher programming constructs, it emphasizes solving long-standing, ‘lower-level’ problems around creating correct and stable code.
Memory Safety
The lack of memory safety and corresponding problems like memory out-of-bound errors are the biggest source of security vulnerabilities and cause tremendous risks and costs. The main cause of the issue is the usage of pointers. It is important to realize how fundamental pointers are for programming, even if not used explicitly, e.g. in every string type (more complex types even more so), array indexes, function calls (pass arguments by reference, function pointers, …), and so on.
Rust introduces a strict ownership concept for variables pointing to other memory locations. In a nutshell, only a single variable can ‘own’ and mutate a value at a time. Multiple variables can reference a value only if all of them are immutable variables, i.e. none of them can change the value. The lifespan (‘scope’) during which a variable owns the value is strictly managed; and when the variable's scope ends, the associated memory is automatically dropped from the heap. This can be analyzed (and errors caught) at compile time.
This also means that Rust avoids using garbage collection in most situations. Consequently, Rust language doesn’t include a garbage collector. For more complex memory management, reference counting libraries are available.
The chapter ‘Further information’ below includes a minimal ‘Scope management «Hello World» example’ plus links to a more thorough discussion.
Concurrency
Of equal if not greater importance is the thread safety built into Rust. The same underlying concept of ownership is applied to ensure that unsynchronized write access to data by multiple threads or thread instances (‘data races’) cannot occur.
Rust features the easy creation of threads that run in parallel, managing shared state and enforcing locking of data, making a distinction between thread-safe and thread-unsafe data types, controlling messaging between threads, and more.
The combination of this set of features (under Rust’s slogan ‘fearless concurrency’) together with the memory safety features are unique to Rust.
Object Orientation
Rust provides features around object orientation. Complex data structures can be specified and encapsulated by a defined set of functions. Also, there are ‘traits’ (similar to Haskell ‘typeclasses’ and to Go ‘interfaces’) that describe common behavior by defining a set of method signatures that are then implemented on different types. This is not quite the same as classic OO inheritance, and allows duck typing.
Technology Evaluation
Choosing a programming language is about balancing (development time) efficiency and (run time) risk. The higher the risk (the more expensive programming errors are), i.e. the higher the focus is on quality, reliability, and correctness, the more Rust should be considered. This is certainly the case, but not limited to, classic system programming tasks like writing device drivers. Beyond that, Rust is well suited for application programming with the above quality focus, but also if certain non-functional challenges exist, like high-performance or low-memory requirements.
Advantages
-
While developing quality code with Rust is a bit more costly (as flaws that would otherwise be caught in run time are already dealt with at compile time), this upfront investment is massively outweighed by the savings in later stages of the software lifecycle.
-
For many tasks, Rust is superior to C.
-
Benchmarks return excellent results for Rust on performance. When replacing C/C++ with Rust for system programs, Software AG has not seen a deterioration of performance (outside the margin of measuring error). As an interesting facet of that, Rust has very good energy efficiency.
-
Unlike earlier improved system languages like D and Nim, Rust seems to have gathered sufficient traction to become the go-to language for the cases described above.
Drawbacks
-
If emphasis is on developer’s efficiency, Rust will not challenge established languages. Python, for example, is dynamically typed, is easy to learn, is brief and elegant and thus easy to read, has a plethora of libraries, …: All this spells ‘efficient coding’.
-
Regarding the learning curve, the following comment of a software engineer is anecdotal but plausible: ‘For the first week or so, we lost much of our time to learning how [Rust] borrows [that is using references as parameters in function calls] worked. After about two weeks, we were back up to 50% efficiency compared to us writing in Go. After a month, we all were comfortable enough that we were back up to full efficiency.’ Software AG’s own experience is similar, in particular if Rust beginners are guided by in-house Rust ‘champions’.
Market – Current Adoption
Rust is a popular language and has been voted as the most-loved programming language for seven years in a row. It enjoys significant momentum with prominent advocates and adopters including AWS and Microsoft. It has even been used to write an operating system (Redox) which claims to be safer and have less errors than any Unix flavor, due to its microkernel design and usage of Rust.
Rust has a lively community (>20.000 entries) which has a reputation to be welcoming due to beginner-friendly rules and active moderation.
Having said that, most of the voters liking Rust are not even personally using it yet. It is not in the top 10 of most used languages today. Experienced developers are hard to find.
Market – Outlook
The benefits of Rust are undeniable. We thus expect its success story to continue.
A notable competitor of Rust is Go. It is ahead of Rust in a number of metrics, including adoption. It is easy to learn and thus suitable for developers of all levels of seniority. It also has a focus on concurrency. For server-side applications, where concurrency is often fundamental but other strengths of Rust are of lesser importance, Go might provide higher efficiency with acceptable risk.
Further Information and Links
Rust Scope Management ‘Hello World’ Example
Consider the following Rust code:
let s1 = String::from("hello");
let s2 = s1;
println!("{}, world!", s1);
The first line defines a variable s1 as a string (remember: implicitly a pointer!) and assigns “hello” to it. The second line defines a variable s2 and assigns s1 to it. The third line prints s1, appending “, world!” to it.
This Rust code will not compile! The line ‘let s2 = s1’ creates a new variable s2 and let it point to the existing “hello” value (in heap). However, no two variables can point to the same “hello” value. This means that the scope of s1 ends and it is invalidated (this is called a ‘move’). The compiler throws an error for the third line (at which time s1 is invalid) and gives information about when s1 went out of scope (line 2).
Remark: It would also be possible to call a clone function to create a second variable s2 pointing to a second, newly created value “hello”, in which case s1 would remain valid and the code would compile. But in that case, s1 and s2 become completely independent and don’t point to the same “hello” in heap.
This is obviously a very simple example, literally the ‘hello world’ of Rust’s scope management. There is much more to it, and the implications of Rust’s scope approach are profound.
Further Reading
The most popular book is The Rust Programming Language which is freely available. It is a good read, if sometimes a bit inconsistent in its level of detail. Impatient readers with software development background who as a very first step want to understand what is unique about Rust can start with Chapter 4. If explains the ownership concept in much more detail.
Another excellent resource is Rust by example.