Summary of Rust vs Go

Rust vs. Go? Which language today offers the magic combination of simplicity and power? Both Rust and Go appear to be systems programming languages, both compile to machine code and both provide stellar performance. So, how do you decide which language is the right fit for your needs?

Rust

Rust went public in 2010, although it may have been conceived much earlier. Rust is often seen as an extension of the ML family of languages. Mozilla was the original underwriter of Rust, and the Servo browser engine (sponsored by Mozilla) was built using Rust. Some of the goals of the Servo project that leverage Rust’s concurrency and ownership advantages were: (i) improved parallelism (ii) better security (iii) increased modularity (iv) superior performance.

Rust 1.0 hit in May 2015. Rust 1.33.0 hit in February 2019. The two largest features in the latest release are “significant improvements to const fns, and the stabilization of a new concept: pinning.”

There is strong community support for Rust. Some examples of community projects include redox, an operating system written in Rust; cgmath, a linear algebra and computer graphics library; and Iron, a concurrent web framework.

Why Choose Rust?

  • Great run speed (comparable with C/C++) – in tests, it has outperformed Go (in some instances, by an order of magnitude faster)
  • Reduced runtime overhead, cutting out garbage collection pauses
  • Strong for tasks in which concurrency, safety and/or performance are critical
  • The complexity of code, which enables fine-grained system control, such as:
    • Rich patterns: slice and range patterns
    • Novel embeddings: postgres and python extensions, crypto libraries, kernels in rust
    • Rich syntax extensions: compile time regular expressions, SQL statements, docopt
    • Novel consequences of move semantics: static freeze/thaw, iterators that consume their containers
    • It has been called “the most loved language by developers” with 73% of developers saying they want to keep working with it
    • Interoperable with C, FFI and other languages
    • Zero-cost abstractions
    • Large supportive community
    • Support for generics in the form of traits
    • Rust has native support for channels between threads and robust compile time thread-safety checking mechanisms (meaning there is no risk of concurrency errors regardless of which data sharing mechanism is used)
    • Simple package management with Cargo, which allows easy access to a range of useful libraries with build-in versioning and complete separation for each individual project

Safety – Rust offers various guarantees in this arena, including:

  • Won’t tolerate unsafe memory access
  • Predictable runtime behavior (no garbage collector, no cost abstractions)
  • Safety against low-level threats such as Null pointers and race conditions
  • Near full control over the hardware, including memory layout and processor features
  • Rust saves time from testing, debugging and crashing

Why Not?

  • Rust involves a steeper learning curve than Go
  • Rust is not simple and needs a serious investment of ramp-up time to learn and master it before most people can usefully handle it; engineer Matthias Ender describes Rust as “hard”, which took him “many months” to become only “somewhat productive”
  • Old habits will likely have to be unlearned before new concepts are learned
  • Go offers more straightforward actor oriented concurrency while in Rust, this is left to the programmer to handle
  • Rust is known for being slow to compile
  • Some missing asynchronous networking functionality in its standard library
  • Rust can be slightly slower than C and C++ in analogous situations

Available Documentation

https://doc.rust-lang.org/book/second-edition/

Golang (Go)

Golang (Go) was conceived in 2007 at Google as a riposte to some of the problems the company was seeing in developing software infrastructure. Problems such as those introduced by networked systems, the web programming model and massive computation clusters were being dealt with via workarounds instead of being addressed directly. Issues of scale had also changed dramatically with server programs needing hundreds or thousands of programmers to comprise tens of millions of lines of code. Build times were also growing in length.

According to Rob Pike at Google, Go was “designed and developed to make working in this environment more productive. Besides its better-known aspects such as built-in concurrency and garbage collection, Go’s design considerations include rigorous dependency management, the adaptability of software architecture as systems grow, and robustness across the boundaries between components”.

It became public in November 2009 and continues to be an open source project. Indeed, Google imports the public repository as opposed to the other way around. Influential predecessors include Hoare’s CSP, Alef, and Pike’s Newsqueak. It achieved 1.0 status in 2012.  Go 1.12 was released in February 2019. Highlights of the latest features include “opt-in support for TLS 1.3, improved modules support (in preparation for being the default in Go 1.13), support for windows/arm, and improved macOS & iOS forwards compatibility.”

Go is in use in thousands of systems worldwide; one of its biggest success stories is that Docker was built using Go.

Why Choose Go?

  • Speed – it is a fast, statically typed language, which quickly compiles to machine code
  • While not always testing as faster than Rust, Go is faster than many other languages, such as Java, C#, JavaScript, Python
  • Simplicity of code
  • Go is concise, pragmatic and efficient
  • The explicit focus of Go is to help make coding easier. In its documentation, it is described as “an open source project to make programmers more productive”
  • The problem-solving approach focused on programmer productivity across the entire software development cycle
  • Flexibility – Go’s unique type system allows for program construction that is flexible and modular
  • Concurrency – Go is focused on concurrency as a first-class concept
  • Simple safety – won’t tolerate unsafe memory access
  • Go excels at writing microservices and straightforward “DevOps” tasks
  • Batteries-included standard library
  • Some interoperability with C and other languages
  • Its rumored goal was to replace C and C++
  • IDE support
  • Simple error handling

Why Not?

  • Go is not a systems programming language
  • Go sacrifices some elements of performance to focus on its goals of simplicity and orthogonality
  • Go allows some interoperability through cgo, however, this is not the expected way for Go programs to be written
  • Go lacks generics
  • It lacks immutability except for a few native types
  • It is garbage collected, which damages performance and makes compile-time error checking less powerful
  • Some say that Go is objectively a “bad language”, Sylvain Wallez, software architect and developer, says that while Go allows for “great performance and reduced memory/cpu/disk footprint”, its design appears to have “happened in a parallel universe (or their Plan9 lab?) where most of what happened in compilers and programming language design in the 90’s and 2000’s never happened”.

Available Documentation

https://golang.org/doc/

Rust vs. Go Case Study – Trial Division

Let’s look at a case study of Rust vs. Go with a simple question: checking to see if a number is prime using trial division. Trial division to determine a prime number involves dividing the number by any smaller natural number to see if there is no remainder. If none is found, it is a prime number.  

Matthias Endler, a backend developer based in Germany, explains how this is done in Golang:

func IsPrime(n int) bool {
   if n < 0 {
       n = –n
   }
   switch {
   case n < 2:
       return false
   default:
       for i := 2; i < n; i++ {
           if n%i == 0 {
               return false
           }
       }
   }
   return true
}
This is how you do the same thing in Rust:
pub fn is_prime(n: u64) -> bool {
   match n {
       01 => false,
       _ => {
           for d in 2..n {
               if n % d == 0 {
                   return false;
               }
           }
           true
       }
   }
}

The solutions are similar in many ways, but there are some key differences, namely:

  • A simple switch-case statement is used in Go; in Rust, a match statement is used, which is significantly more powerful
  • A simple for-loop is used to iterate over the numbers 2 to n in Go; in Rust, a range expression (2..n) is used
  • Go uses two return statements; in Rust there is only one return expression. Most things in Rust are expressions, which can be returned and assigned to a variable. The structure of expressions dictates the structure of execution.

Rust is overall more functional than Golang. The above code could be rewritten using any method instead of Range, for instance:

fn is_prime(n: u64) -> bool {
   match n {
       01 => false,
       _ => !(2..n).any(|d| n % d == 0),
   }
}

Examples courtesy of Rosetta Code (many more available here as well).

Conclusion

Either language works well if you’re designing a web service that needs to handle a high volume of traffic, which you want to be capable of scaling both vertically and horizontally. According to many in the industry, Go is faster to learn, so it is probably the better choice of language if you have a large developer team or many services to write. Neither Go nor Rust tolerates unsafe memory access.

Rust has been described as “a superior language to Go in, quite literally, every single way possible” and “almost bulletproof when compared side by side to literally any other programming language”. However, Go is more widely popular, in part due to its relative simplicity and low ramp-up time.

The two languages have been seen as competitors, partly because they came out at around the same time, but as we have seen, this is not necessarily so. Go keeps the focus on simplicity and uniformity allowing the developer an easier programming experience. It makes large programming teams more efficient through a rigid application of simplicity. Rust, meanwhile empowers developers to take control at a granular level, from controlling how their threads behave with the rest of the system to the lifetime of their variables.

Rust competes for space with C++ and D i.e. existing in a realm of greater complexity, for programmers who are prepared to accept more complex syntax and semantics in return for the best possible performance, such as microcontrollers, AAA game engines, and web rendering engines.

Go, meanwhile, is more of a competitor with the post 2006 Internet 2.0 generation of companies who want a simpler solution than JVM based languages and have outgrown those such as Ruby, Python and Node.js (v8).

Digiprove sealCopyright secured by Digiprove © 2020