Ian Patrick Badtrousers

Rust and Go are blood enemies!

This post is a response to Why Go and Rust are not competitors, by Dave Cheney.

The original post is very much on point, I highly recommend you to give it a read! There’s also a lovely biased discussion on Reddit.

Both Go and Rust solve exactly the same problem: painful engineering, so apparently both came here to make our lives easier. Go has adorable concurrency primitives and green threads and stuff. All in all, it made programming sort of fun, since Go code is a pleasure to read. In the meantime, Rust gave us powerful zero-cost abstractions for pattern matching.. and traits! Sounds reasonable, ain’t it? Jokes aside, Rust made tricky things much easier (a common misconception: it didn’t make them dissapear). Its devil’s type system offers you guaranteed memory safety and ability to get rid of data races, which sounds bizarre. Fun will remain fun, but remember: you’ll always have to pay.

IIRC, Rob Pike once said he had been genuinly surprised with how things turned out; Go was expected to become a lifebuoy for C++ programmers, but eventually people had started thinking of it as of replacement for Ruby/Python. In my humble opinion, that’s great, it couldn’t turn out better! Think about it: cool kids switching from Ruby to a real programming language? Alright, so what does Rust have to do with all that? Rust seems like a solid and safe replacement for C++ and the whole thing hardly has anything to do with Go. So why would you want them to compete? Because of reasons.

  • Both appeared at relatively the same time, both brand new
  • Both came here, so we could be able to write reliable software
  • Areas of application do heavily overlap

For those of you who think that the biggest problem of C++ is its “unsafe” nature (let’s pretend modern C++ programming isn’t based on safe smart pointers) are totally wrong. The biggest trouble of C++ is that the code is hard to read, debug and maintain. Believe it or not, memory management is rather an imaginary issue—C++ offers a couple of ways of getting it right. The whole mess hardly has anything to do with the memory management at all. Tbh, Rust is no different. You wouldn’t solve this major issue by introducing way more and more and more new fancy entities, you’d just make it even worse. Go does an awesome service here: less is exponentially more.

Talk’s cheap, show me the code! Alright then, let’s take a look at some real-life code in Rust. I skipped the comments for this code listing, but the whole thing looks pretty much like this:

#[cfg(test)] use std::io::{File,MemReader};
#[cfg(test)] use std::str::from_utf8;

pub trait SliceContains {
	fn contains_slice(&self, needle: &[u8]) -> bool;
	fn contains_slice_pos(&self, needle: &[u8]) -> Option<uint>;

impl<'a> SliceContains for &'a [u8] {
	fn contains_slice(&self, needle: &[u8]) -> bool {

	fn contains_slice_pos(&self, _needle: &[u8]) -> Option<uint> {
		if self.len() < 2 { return None; }
		for i in range(0, self.len()-1) {
			if self[i] == 10 && self[i+1] == 10 { return Some(i); }

You know, tbh impl<'a> Foo for &'a [u8] is nuff said already. Each time I look at such a crazy piece of “code”, all I want is to find great man Rob Pike and shake his manly hand! Honestly, thanks for not putting this sort of unmaintainable rubbish into the language. We may love or hate Go, but everyone must be grateful to Go team for not making the language this bad. Just to clarify things out, by this bad I mean that Rust bad. If I’m not mistaken, Rust was supposed to become something like a modern alternative to C++. I’m not sure if it’s true though, but apart from everything else, Rust has definitely inherited the worst feature of C++ language—crazy unreadable stuff lying all around.

This article would’ve been incomplete without the corresponding code listing of some code in Go. There’ll always be dozens of ways to do one particular thing or another in the scope of a programming language. Frankly, advocates will always find legit counterarguments to your arguments against these ways. That said, I didn’t bother to look for a symmetric code snippet and just picked a random one from the Docker codebase.

func Generate(pattern string) []string {
	re, _ := regexp.Compile(`\[(.+):(.+)\]`)
	submatch := re.FindStringSubmatch(pattern)
	if submatch == nil {
		return []string{pattern}

	from, err := strconv.Atoi(submatch[1])
	if err != nil {
		return []string{pattern}
	to, err := strconv.Atoi(submatch[2])
	if err != nil {
		return []string{pattern}

	template := re.ReplaceAllString(pattern, "%d")

	var result []string
	for val := from; val <= to; val++ {
		entry := fmt.Sprintf(template, val)
		result = append(result, entry)

	return result

I could tell what the function above does straight after skimming through it. Needless to say, it takes a couple of seconds. Go doesn’t really add anything conceptually new! That’s why people coming from different backgrounds don’t struggle a lot here—they are already familiar to most of the concepts. Isn’t it amazing?

Go wins.

Published: Tuesday, 7 Jul 2015

This post allows opt-in commentary, powered by Disqus.