Rust vs. C++: A Pragmatic Perspective on Time-Saving Efficiencies
- Rust Matters
- Feb 3
- 5 min read
By Edward Bird
I'm not of the opinion that any programming language is perfect. Programming lanaguages are tools. I am more interested in what I can build using the tool using the tool itself.
With that said, some tools are easier to use than others. I would rather cut wood using a circular saw than a hand saw. It is quicker, and gives similar results. I choose the circular saw, because it saves time.
There's a lot to like about Rust. However, allow me to give a balanced and pragmatic view of my experience using it. Afterall, it is a tool, and may not be the best choice in all contexts. It is, however, a good choice in many contexts.
I started using Rust when I joined a Hedge Fund in 2023. It was a startup, and I was hired to build an order management system. The Hedge Fund engaged in systematic trading. The purpose of the order management system was to manage and net order instructions produced by other components in the system, and to execute these orders in the market. It did other things too, such as manage risk calculations.
8 months after joining, I had built a working product. How was it that this was achieved? Broadly speaking, there are two factors driving this success.
The first factor was the use of Rust, and the leveraging of the time saving features which it offers. More on this later.
The second factor was that I chose to write simple code. Why make a system more complex than necessary?
On this point, my advice to other Software Engineers is keep your designs simple. You can always make a simple system more complex, but it is much more difficult to make a complex system simple again.
I joined the Fund with no prior knowledge of Rust. However I did have a solid C++ background.
I can't understate the importance of this. The raison d'etre for Rust, in particular the borrow-checking syntax, is C++. The borrow-checker is a set of rules which impose additional constraints on the programmer, and therefore reduce the set of all possible legal programs.
What does this mean? This means that the set of possible legal programs which it is possible to write in C++ is larger compared to Rust. To make the statement less abstract, you can write code in more possible ways in C++ compared to Rust.
This sounds like Rust is at a disadvantage - but it isn't. Think about it this way: It possible to express some programs using assembly language which cannot be expressed using the C language. The C language has more constraints than pure assembly language code would.
This is not a disadvantage, but an advantage. We have had functions in programming since the 1960s. Functions constrain the programmer by limiting execution flow throughout a program. Functions, when implemented using a FILO queue, aka stack, constrain the order in which the programmer can jump from one region of code to another.
A function call makes the stack one level deeper. Returning from a function is the reverse operation. When you return from a function, you cannot return to an arbitrary place in the code, you can only return to where you have come from. This is a constraint, but usually we don't even notice it.
There are three existing programming pardigms. Structured Programming (the use of if statements, for loops, etc), Object Oriented Programming (allocating variables on the heap rather than stack such that data can outlive a function call), and Functional Programming (constraining mutability). Each of these were discovered over a period of time in the early days of computer programming.
Arguably, Rust introduces a new one. The concept of constrained ownership, and constrained borrowing of ownership.
Much of what I have said in relation to Rust so far has been somewhat theoretical. Allow me to say something more practical.
If you are a Rust programmer, and have not used C++, I would encorage you to start an experimental project using C++. By doing this, you will experience some of the problems which C++ has which Rust solves.
For example, in C++, the compiler will allow you to call a function, create some data on the stack, and return a reference to that data. This is of course nonsensical. As soon as the function returns, the stack frame allocated for the function, along with its data, is no longer valid. This creates undefined behavior. The constraints imposed by the Rust borrow checker will not allow this.
I would imagine that if someone started working with Rust and did not have a C++ background, then the language would appear somewhat esoteric, and constrained. Perhaps I am wrong. If you feel this way, then experimenting with some C++ will probably provide some insight.
Rust offers other efficiencies too. Rust enum types are type-safe, unlike the C++ alternatives. They are also a convenient mechanism for working with a group of data, where the group of data needs to be able to represent multiple different types. This is convenient for handling the requirement to return multiple types of data from a function, along with many other applications. It can be used as an alternative to inheritance based polymorphism.
The built-in optional and result types are two other such examples. The option type is used to represent data when the data can be nullable. The result type offers a way to handle errors using function return values, rather than by emitting exceptions.
There are other nice language features too, such as pattern matching, and the requirement to use return values rather than accidentally ignoring them. Further, Unit Tests can be written in the same file as the code they test. The integration of Rust with IDEs such as VS Code is excellent as well.
Finally, Cargo is worth mentioning. Cargo is the Rust package manager. It is similar to Python pip. It is a convenient tool which manages project creation, installing project dependencies, running tests and building. C++ does not have a standardized package manager or build system. This may be Rusts most significant advantage compared to C++.
I have skimmed over some of these concepts. Overall, the take home message is this. Rust can save you time. I would rather spend 5 minutes using Cargo than several hours manually managing dependencies with CMake. I would rather load VS Code, and have the integration with a Rust project "just work" without needing to configure VS Code manually. I would rather write an Rust enum than a C++ variant. I would rather work with Rust modules, which enforce filesystem structure, than C++ namespaces which do not.
Rust is not perfect, and the borrow checker sometimes prevents me from writing code which it would have been possible to write in C++. But overall it's pretty good, and does offer many advantages compared to a language such as C++.
The time saving efficiencies are very much missed when I start a new C++ project.
_
Thank you so much to Edward for sending it this blog, we appreciate it so much! If you have a blog to share, please send it to Patrycja@umatr.io
Comments