Disclaimer: this post isn’t meant to be a part of Programming Languages holywar or to say that either of languages is better. My goal is to outline the good things I love about Rust, which C and C++ do not have. Both C and C++ are amazing programming languages with a wide range of use scenarios.

Rust programming language

Rust is a modern programming language, which recently received much attention and became quite popular. It is mostly focusing on guaranteeing safety and being exceedingly fast, which makes it a perfect match for programming systems and writing relatively low-level code.

Background

I’ve started programming in Pascal and C# 2.0, then transitioned to Java and later to Python, doing some web in Javascript (and such). I only started C++ after several other languages despite the most “usual” path starting from C++ into another language. I’ve spent a lot of time hacking C++ compilers, exploring compilers, interpreters and doing LLVM-related things. I’ve done C, Assembly language, Lua, and Delphi for short while, too. Today I mainly code in C++ (most projects) and Python (which I use for Data Science, Machine Learning projects and scripts, because I absolutely detest Bash).

I do consider myself a C++ programmer after all since I’m doing much in Clang and I have to understand complicated language structures, its internals and where it’s going in the future in details.

I started writing some code in Rust around a year ago when I was excited about yet another programming language front-end built on top of LLVM.

Rust features

One compiler to rule them all

rustc is The Compiler for Rust and it’s amazing! While there are some alternative Rust implementations, those are mainly made for fun while rustc remains the main one. One thing that is also good is that rustc is based on LLVM. LLVM is currently state-of-the-art compiler back-end. Sticking to LLVM adds many points to Rust potential in my opinion.

One of the problems C and C++ have to face is that there are too many compilers and most of them are horrible. Developers have to use obsolete standards (e.g. C++03 and even C++98) just because some compilers do not (fully) support modern ones. This prevents migration to newer standards and makes it harder to write good-quality code. There is also a number of closed compilers, which doesn’t make things easier. GCC implements its own language extensions and while many projects make use of them it forces other compilers to support these extensions, sometimes they conflict with new standards and it makes things even more complicated. MSVC (until recently) couldn’t fully comply with C++11 and many projects dependent on Windows MSVC builds had or even now have to prohibit the the use some features in order to build with MSVC. To some degree, C++ compilers do very different things, some of which disrupt stability of the project builds on different platforms using different toolchains.

Uniformly Accepted Practices and Learning Curve

Rust comes with The Rust Book, which serves two purposes. First, it makes a smooth yet precise introduction to Rust Programming Language. Second (and in my opinion most importantly) it introduces Best Practicies™ of writing high-quality Rust code. This is just perfect! Both C and C++ are suffering from numerous guidelines telling opposite things. E.g. Google C++ Style Guide recommends not using unsigned types while C++ Core Guidelines recommend using unsigned types on several occasions. I can think of many more cases where using unsigned is good (for example, logically some values can not be negative, so giving up and additional bit hurts logic, readability, and effectiveness).

Having a single style guide, which is accepted by the whole community is a huge win. There are formatting guidelines, guidelines regarding the code, recommendations on high-level architecture matters and so on.

Safety

The common problem of large codebases implemented in C or C++ is leaking memory, even after C++ introduced RAII and tried to reduce the use of raw pointers and made an effort to suppress the ability of programmers to mess up with the memory. Rust takes the idea of safety to the extreme. There are several mechanisms preventing developers from writing vulnerable code, making them almost unable to cause programs to leak memory, taking care of all references and making sure that there are no “dangling references”. The idea is simple: the unsafe code simply won’t compile. rustc will produce a number of warnings and messages making the developer think about one’s bad behavior for a while. In rare cases, one might use unsafe Rust constructions, but in 99.9% cases these are not necessary and therefore the number of vulnerabilities a piece of software may have tends to zero.

Compiler Messages

Three cheers to rustc’s human-readable error and warning messages! Unlike C and C++ compilers, rustc provides a good explanation of what’s wrong with a the particular piece of code, kindly highlighting the affected char range and giving some hints:

error[E0308]: mismatched types
  --> src/main.rs:11:32
   |
11 |     let URL = match Url::parse(matches.value_of("URL")) {
   |                                ^^^^^^^^^^^^^^^^^^^^^^^ expected &str, found enum `std::option::Option`
   |
   = note: expected type `&str`
              found type `std::option::Option<&str>`
   = help: here are some functions which might fulfill your needs:
           - .unwrap()
           - .unwrap_or_default()

error: aborting due to previous error

error: Could not compile `example_project`.

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

For an inexperienced programmer, it often is very hard to understand what’s wrong with the piece of C++ code the compiler rejected and the output message doesn’t make any sense. rustc is very friendly and helps beginners a lot.

Toolchain

Using a programming language is much more convenient with the right tools. Rust has a great ecosystem, which makes programming more pleasant.

Build system & Dependencies

Cargo is Rust’s build system and package manager. Cargo downloads dependencies and builds projects. It is extremely easy-to-use and provides all the necessary facilities for creating and maintaining projects.

Cargo helps with other things, too. It is illegally easy to setup proper testset and benchmarks! Cargo helps with these, too.

For testing, one can add standalone tests and test the expected behavior of documented modules! For example, one can document a function telling what it is supposed to do and add few examples. These examples will be run as tests! That’s so good! Documentation as tests discusses that a bit more.

Benchmarking is really easy, too. Seeing whether some specific changes improved the overall performance of the project is sometimes not trivial, but Rust developers took care of it and one can have a fairly trivial setup benchmarks. After that, seeing whether the project became better over a sequence of changes is very simple. As an example, take a look at faster sorting algorithm PR merged into rustc.

Documentation

rustdoc is a tool, which generates documentation. Rust has simple documenting rules, which are enforced by this tool. It generates shiny documentation and is really easy to setup in one’s project. Unlike C and C++, which have several documentation tools and a number of documentation rulesets, Rust only has one, which is an advantage. It also comes with Cargo, so one doesn’t have to make any effort to set it up at all.

Rustup

rustup is an installer for Rust. It keeps rustc updated, it can manage several versions of rustc(stable, nightly, beta) and is similar to Python’s virtualenv.

Continuous Integration

Rust projects benefit from the simplicity of setting CI up. Travis CI, which is most used CI system on Github is plain simple to setup with Rust! Due to Cargo and rustup, there’s no need to mess up with target platform and compiler version.

Just take a look at Boost.Hana’s Travis CI script. That’s how much one has to do in order to test everything using many versions of modern C++ compilers. In comparison: this is how most Rust setup scripts look like. Plain simple!

Formatting

Rust has both formatting guidelines and the tool to enforce these: rustfmt is there whenever one would like to improve formatting in one’s project. rustfmt helps to maintain readable codebase and can be used from a text editor (such as Vim, Emacs, Sublime Text 3, Atom or Visual Studio Code). The user can create custom configurations and easily setup style check using rustfmt.

Static Analysis

Even though rustc does amazing job at analyzing potential vulnerabilities Static Analysis can help even more!

There are always pieces of code, which can be simplified either in order to improve readability or to comply with the widely accepted practices. rust-clippy has a number of checks making development more fun. It detects the pieces of code where a programmer probably meant something else and suggests necessary fixes. Keeping a project clean and safe was never so easy!

In C++ there are several good Static Analyzers, e.g. clang-tidy, but it’s not too user-friendly. Although many good projects use it (and that’s actually one of the reasons they’re good) it isn’t a widely accepted practice. Many projects suffer from not having CMake as their build system, which makes clang-tidy much harder to setup. All in all, if people used Static Analysis tools more in C and C++ projects, we wouldn’t have Heartbleed and a number of other horrible bugs and vulnerabilities. With Rust it’s just more common and infinitely easier.

Community

The Rust Community is very friendly and welcoming. There are several resources aiming to improve the learning curve. The developers also care about newcomers a lot: e.g. when the Rust community realized The Rust Book was too hard for newcomers, it was rewritten (and it’s being rewritten right now if I’m not mistaken). Rust by Example is another book made by Rust developers to learning process more entertaining. This Week in Rust covers latest changes in Rust, highlights the best project of the week and embraces the newcomers willing to help The Rust Community by providing a list of issues, which can be easily fixed, where a mentor would help those willing to contribute. Learning Rust is really an exciting process!

Speed of Language Development

Rust is constantly being improved and it gains new features with unbelievable speed. At the same time, I support the wish of the developers to keep the Rust core neat and clean while providing additional features as external crates and semi-official modules. While C++ core is getting tremendous with associated Laguerre polynomials, beta function and Riemann zeta function being integrated into 1000+ A4 pages ISO Standard, Rust keeps it simple. But this doesn’t mean that you can’t get those in Rust! Just pick a crate, which you need, and you’re all set! There are hundreds of useful Rust crates.

Language Standard

The language has a number of amazing features not yet merged into C++ Standard.

Traits

Traits are the amazing mechanism allowing more generalization. C++ is going to have Concepts at some point, but right now there aren’t any and there is a number of drawbacks connected with that. For example, many C++ Standard Library functions accepting parameters of some special type aren’t able to check whether passed parameters are having the correct metatype efficiently, e.g. special iterator metatype (ContiguousIterator, RandomAccessIterator, etc). std::sort functions look like this:

template< class ExecutionPolicy, class RandomIt >
void sort( ExecutionPolicy&& policy, RandomIt first, RandomIt last );
template< class RandomIt, class Compare >
void sort( RandomIt first, RandomIt last, Compare comp );
template< class ExecutionPolicy, class RandomIt, class Compare >
void sort( ExecutionPolicy&& policy, RandomIt first, RandomIt last, Compare comp );

With Rust it would’ve been much cleaner.

Modules

Modules are a nice way to organize the code and allow incremental compilation as well as many other great things. These are not yet merged into C++ but are planned.

Existing Issues

Even though Rust is amazing, it has several issues. Here are some of them:

While being a C++ programmer, I do like the power C++ Templates give me. Unfortunately, Rust generics aren’t as powerful. As a result, there is a number of ugly specializations, such as std::tuple. Parameter pack is a simple trick to avoid such patterns, but Rust doesn’t have such mechanism yet.

Compared to C, Rust doesn’t provide support to some exotic platforms, because it relies on LLVM in code generation. LLVM starts to support more platforms and it’s likely to fix this issue in the future, but in the mean time projects heavily relying on exotic platforms are likely to choose C for a number of different reasons.

Rust doesn’t have classical OOP model with classes and inheritance. Instead, there are structs, which is a little uncomfortable at first. Rust also doesn’t have function overloading, which is a little overwhelming, but there are ways to deal with it.

However, I believe the existing issues are not crucial and they will be fixed eventually. One simply can’t do everything right at first.

Conclusion

Rust is a very young language and it is fortunate not to repeat a number of mistakes C and C++ had in the past. C++’s present is dictated by its past a lot and there aren’t many things we can do about it. Both C and C++ are necessary and there is a number of scenarios where they are the best choice, but I am happy to have Rust programming language as an alternative and I am happy to see it becoming better and better.

Rust seems very promising to me and I expect to see more and more tools, such as ripgrep, implemented in Rust and proving to be faster, safer and easier to maintain. I believe that Rust is, in fact, the future of low-level tools and systems, the actual future we deserve.