Ian Patrick Badtrousers

Go and Rust 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.

Go and Rust seemingly share the objective to solve exactly the same problem: the painful and sturdy engineering experience prevalent in the domain of system engineering. I guess it’s safe to say that in one way or another, both languages came here to make our lives easier. Go has adorable concurrency primitives, C-like simplicity, and stuff like that. All in all, it made this particular brand of programming fun again! It’s true that Go code is a pleasure to read, if not to write. In the meantime, Rust gave us powerful zero-cost abstractions for pattern matching.. and traits! Sounds reasonable, doesn’t it? Jokes aside, Rust made some incredibly tricky things much easier (a common misconception: it didn’t make these things go away altogether!). Rust has a devil’s type system which offers you guaranteed memory safety and ability to get rid of data races without the use of GC or manual management, and yes it does sound a little bit bizarre. What’s fun will stay fun, but remember: you’ll always have to pay, one way or another.

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 the abovementioned reasons.

  • Both languages appeared in the mainstream at approx. the same time;
  • They both share the objective to simplify how we write reliable software;
  • Despite commonly held beliefs, their 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 written in Rust. I intentionally skipped the comments for this code listing, but the whole thing is 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] {
	#[inline(never)]
	fn contains_slice(&self, needle: &[u8]) -> bool {
		self.contains_slice_pos(needle).is_some()
	}

	#[inline(never)]
	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); }
		}
		None
	}
}

You know, to be honest here, impl<'a> Foo for &'a [u8] is ‘nuff said already. I’ve been involved with Rust soon from the inception and I like it very much, but every single time I gaze meaningfully at things like this, all I want is to find my man Rob Pike and shake his manly hand! Honestly, all jokes aside, thanks for not putting this rubbish into what’s called Go. We may love or hate it, but everyone must be grateful Go team cared enough, or perhaps didn’t care too much—to make the language this bad. Just to clarify things: by this bad I mean 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 some of the worst C++ language—crazy unreadable style lying all around.

This article would’ve been incomplete without some of the Go code listing. Disclaimer: there are, of course, many ways one would want to do some thing in the scope of a chosen programming language. The advocates would always be able to find legit counterarguments to your cutting knieving 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 seconds into skimming through it.

Well, it’s almost as if Go doesn’t actually add anything conceptually new! And it’s almost as if that’s why people coming from different backgrounds don’t struggle too much with it—apparently, they are already familiar with most of the concepts. I think this is amazing, especially moreso for the tight and hardly clearly approachable domain that is system programming.

Go wins!


Published: Tuesday, 7 Jul 2015


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