Pros and Cons of Rust and Go

One expert’s take on the Pros, Cons, and Controversies of each language.

If you have written code in either Rust or Go, you’ll recognize some similarities and differences between them. While there is some overlap between the goals of the two languages, there are plenty of differences between the two. Each language offers benefits depending on the problem you’re trying to solve.

We spoke with Damien Stanton, a software engineer who has gained experience in both languages. His exposure to these languages began in 2014 when he was working on a project that required the ability to compile native static binaries. Since Go and Rust both offered the ability to compile native static binaries that could be easily deployed, he delved into the pros and cons of each.

Since that point, Damien has repeatedly found himself at the junction of these two languages. While the majority of his professional programming experience has been with Go, he’s been interested to see the Rust community’s approach to various problems, including error handling, generics, and concurrency.

As a result, he spent a significant amount of time delving into both languages. His research led him to present “Rust from Go’s Perspective to the Golang DC Meetup community.

Our conversation with Damien delves into various aspects of the two languages: their differences, similarities, and some of the common controversies between the two.

The conversation below has been edited for length and content.

 

What are some of the similarities between these languages? Where would you say the overlap exists?

Both ecosystems are trying to solve a lot of the same problems.

They’re both positioned somewhere between a lower-level systems language (like C or C++) and a runtime-based language (like JavaScript or Python). Both languages lean towards the systems programming realm.

I think that ease of deployment and ease of cross compilation is a big thing that both languages do very well. Memory safety is also important to both languages. They both naturally solve problems where you need high level performance or high level concurrency; stuff that’s traditionally hard to do in Python or Java.

Each language takes a very different approach, especially with memory management. But, having code that is stable, inherently reliable, and easy to maintain and upgrade is something they each do well.

In 2020, it seems like a lot of the community is saying it’s good to have both tools and use them to solve separate problems. So where would you use each language now, knowing the capabilities of each?

  • Coding with Go: There used to be a view that Go was a “user-friendly C.” But in terms of how I’ve used it and how I see it currently used in the community, Go probably is a better successor to Java since it’s useful for building distributed systems. Go is useful for building servers and distributed systems architecture. That’s the reason that Kubernetes, Docker, and all these other systems were written in Go to begin with.
  • Coding with Rust: This language is especially useful in time/space-constrained scenarios, like microcontrollers. Another valuable use of Rust is web assembly. There’s a ton of action in the Rust community around building tools that compile to web assembly and run in a browser. I think Rust is more akin to C++ in terms of the kinds of problems in which it feels natural.

When it comes to choosing between the two languages, I think in some ways it’s more about your programming background than the specific problem you’re trying to solve. You could probably frame most problems in a way that would fit into a Rust codebase or a Go codebase.

In my experience at a startup, we chose to use Go, especially when we were in a period of rapid growth because it was easy to pick up. New team members could quickly start contributing and help build systems.

That’s definitely not exactly the case for Rust. It has a steeper learning curve due to its unique memory model and can feel difficult to pick up. I’ve found that teams with a C++ or Java background will likely pick it up quickly. It seems to draw people who come from “big” languages rather than “small” ones, if that makes sense.

While there are good, arguable use cases for one over the other, the decision often boils down to the operational dynamics of the people as much as the technical side.

 

There’s a lot of discussion surrounding the Rust and Go programming languages. What are some popular topics that stand out to you?

Go Generics

A common complaint that’s been tossed around since v1.0  in the Go community is the lack of generics. Rust, on the other hand, has a powerful type system with support for generics. It comes from a very different design philosophy than Go’s, with a type system inspired as much by Haskell and ML as C++.

In the Go community, the approach to generics is slowly coming together. During GopherCon 2019, there was a talk proposing a syntax for Go generics. I think a lot of people aren’t aware that it is being actively worked on. It’s possible that we’ll see generics in Go before v2.0 (somewhere between 1.16-1.19 if I had to guess).

Concurrency

Concurrency has changed a lot in the Rust community in the last year, and even in the last six months.

A common discussion point between Rust and Go users has been concurrency. Go has this ultra-simple concurrency model, with goroutines and channels, while for a long time Rust had a simpler multithreading model. It is similar to C++ or Java, but with some nicer facilities for inter-thread communication, like MPSC channels, which are very much like Go channels

But now, the Rust ecosystem has moved towards a model of futures, which brings it inline with the way it works in Python, JavaScript or C#. Let’s say you have some sort of task executor and you mark a function as async. The function will be completed sometime in the future and you want to wait for the result. Once you get the result back, you can continue. People really love that async/await model since it lets you write code that looks and feels synchronous but gets executed asynchronously. The futures model is quite powerful.

It’s also leapfrogged a little bit. You can write your own task executors in order to control the algorithm. That’s akin to having your own goroutine scheduler.

Rust also has a pretty powerful macro system, which makes it possible to have the compiler do a lot of work and do code generation that would be pretty onerous or dangerous to generate in Go. In Rust, there are more knobs to tweak! While this is good for solving a big range of problems, it means there’s a lot to learn. Like anything else, it’s a tradeoff.

Go’s Build Tooling

This has long been a complaint among Go programmers. At work, we just recently switched to Go modules. Our experience with this migration was a good one, but we’ve read plenty of horror stories. Overall Go’s tooling works great, but it (like the language itself) is very simplistic. Modern developers want things like a stable language server for their editor, an easy to use dependency management solution, and good automatic documentation and publishing tools. Some of these things work well in the Go ecosystem, but others do not. We’ve had some issues with the language server gopls, for example. Rust, on the other hand, doesn’t really seem to have any of these issues with the cargo tool. It just works, it produces great documentation, it’s easy to extend with sub-commands.

Fuschia: Google’s Successor to Android

An interesting use case regarding Go versus Rust was Google’s new software, Fuschia, that will eventually replace Android.

Google is building the system mostly in C++, but there are some Rust components that are from ChromeOS, which has a lot of Rust in it. To determine how users would write programs for Fuschia (that is, userland programs rather than a kernel component), they investigated five languages including Go and Rust. For this use case, Go’s memory management overhead caused too much latency. This was a common issue with the memory-managed languages they reviewed, and in the end, one can only write user-facing code in C++ or Rust.

Release Cycles

These two programming languages have very different approaches in their release cycles.

  • Go’s Release Cycle: Go’s release cycle is somewhat regular, but it is also a black box; No one outside the core team really knows when a new release is coming out. Typically, it’s just a blog announcing the release. There’s plenty of documentation in the form of the raw Gerrit/GitHub issues, but this is the limit of transparency.
  • Rust Release Cycle: In the Rust community, it’s somewhat more transparent. The core team records all of their team meetings on YouTube and broadcasts them, so you can actually see what they’re discussing / triaging. It’s certainly interesting to see the thought process behind a major language. Rust has a well-defined rolling release cycle, with a nice stable/beta/nightly delineation.

I don’t know if one approach is necessarily better than the other, but they’re certainly different. I personally tend to think that having everything fully open and transparent is probably better in the long run.

Sometimes the motivations of technical decisions in the Go language can be confusing or not make sense. Some people have an adverse reaction to a technical decision sort of not allowing any debate; the core team members say so and that ends up being the law more or less. This isn’t pedantic though, it’s a core design philosophy for Go. The lack of outside influence has led to the language remaining very simple and slow-changing.

In sum, it’s interesting to see how their organizational styles are so different, yet both languages have had so much success. Go and Rust are both fantastic languages, and I hope new and experienced programmers in both communities can get together more and learn from one another!

Author: Lauren Alexander

More Related Insights