Why is Rust revolutionary?
With programming, there is usually a trade-off between speed and resources and development speed and safety. Low-level languages such as C/C++ can give the developer fine-grained control over the computer with fast code execution and minimal resource consumption. However, this is not free. Manual memory management can introduce bugs and security vulnerabilities. A simple example of this is a buffer overflow attack. This occurs when the programmer does not allocate enough memory. For instance, if the buffer only has a size of 15 bytes, and 20 bytes are sent, then the excess 5 bytes might be written past the boundary. An attacker can exploit this by passing in more bytes than the buffer can handle. This can potentially overwrite areas that hold executable code with their own code. There are other ways to exploit a program that does not have correctly managed memory. On top of increased vulnerabilities, it takes more code and time to solve a problem in a low-level language. As a result of this, C++ web frameworks do not take up a large share of web development. Instead, it usually makes sense to go for high-level languages such as Python, Ruby, and JavaScript. Using such languages will generally result in the developer solving problems safely and quickly.
However, it must be noted that this memory safety comes at a cost. These high-level languages generally keep track of all the variables defined and their references to a memory address. When there are no more variables pointing to a memory address, the data in that memory address gets deleted. This process is called garbage collection and consumes extra resources and time as a program must be stopped to clean up the variables.
With Rust, memory safety is ensured without the costly garbage collection process. Rust ensures memory safety through a set of ownership rules checked at compile time with a borrow checker. These rules are the quirks mentioned in the following section. Because of this, Rust enables rapid, safe problem-solving with truly performant code, thus breaking the speed/safety trade-off.
Memory safety
Memory safety is the property of programs having memory pointers that always point to valid memory.
With more data processing, traffic, and complex tasks lifted into the web stack, Rust, with its growing number of web frameworks and libraries, has now become a viable choice for web development. This has led to some truly amazing results in the web space for Rust. In 2020, Shimul Chowdhury ran a series of tests against servers with the same specs but different languages and frameworks. The results can be seen in the following figure:
Figure 1.1 – Results of different frameworks and languages by Shimul Chowdhury (found at https://www.shimul.dev/posts/06-04-2020-benchmarking-flask-falcon-actix-web-rocket-nestjs/)
In the preceding figure, we can see that there are some variations in the languages and frameworks. However, we must note that the Rust frameworks comprise Actix Web and Rocket. These Rust servers are in a completely different league when it comes to total requests handled and data transferred. Other languages, such as Golang, have come onto the scene, but the lack of garbage collection in Rust has managed to outshine Golang. This was demonstrated in Jesse Howarth’s blog post Why Discord is switching from Go to Rust, where the following graph was published:
Figure 1.2 – Discord’s findings => Golang is spikey and Rust is smooth (found at https://discord.com/blog/why-discord-is-switching-from-go-to-rust)
The garbage collection that Golang was implementing to keep the memory safe resulted in 2-minute spikes. This is not to say that we should use Rust for everything. It is best practice to use the right tool for the job. All these languages have different merits. What we have done in the preceding figure is merely display Rust’s merits.
The lack of need for garbage collection is because Rust uses enforced rules to ensure memory safety using the borrow checker. Now that we have understood why we want to code in Rust, we can move on to reviewing data types in the next section.