I've been using the Go programming language for about a year now, and I think everyone should be using it. Here are some of the reasons why:

About Go

Go is "a compiled, concurrent, garbage-collected, statically typed language"1 designed by Robert Griesemer, Rob Pike, Ken Thompson, and Russ Cox at Google. It was created as a systems language that would address some of Google's biggest software engineering problems, including slow builds, (almost) unmanageable dependencies, and many other inefficiencies.2 Go 1, the first long term, stable version of Go was released in March of 2012. It's been about a year and a half, and many well respected companies (besides Google) are already using Go in production environments including Canonical, Heroku, Soundcloud, Bitly, and many others.

Go Basics

Assignment

Go is statically typed, but it has some conveniences that make it feel more dynamic. Consider the following examples:

// explicit type declaration and assignment
var count int = 5

// implicit
count := 5

// implicit multiple assignment
count, err := countSomething()  

The second and third examples use Go's type inference, meaning the variable(s) are declared with whatever type the right hand expression returns.

Objects

Go isn't really object-oriented, it's more like C in this regard. But it does allow something similar by attaching functions to specific types. (follow the "play" links in the upper-right of these examples to see them in action).

package main

type Vehicle struct{}

func (v Vehicle) Move() {  
  println("vehicle moving")
}

func main() {  
  new(Vehicle).Move()
}

The func (v Vehicle) Move() syntax declares a function called Move that takes no arguments and has no return values and attaches to the type Vehicle. Additionally, the specific Vehicle object that the function is called on is referenced by v inside the function.

The Go Way

Go is designed to be a small but complete language. The developers have spent a lot of time figuring out what doesn't need to be in the language. The result is that people new to Go are often dismayed at the absence of some features, and people who have been using it for a while love the absence of those same features.

Types

The most prominent of these "missing" features is probably a type hierarchy as implemented in most object-oriented languages. By design there is no inheritance. According to the Go authors, "it is our opinion that the [inheritance] model has been overused and that it is worth taking a step back."4 However, a similar (but simplified) relationship can be defined with "composition."

package main

type Vehicle struct{}

func (v Vehicle) Move() {  
  println("vehicle moving")
}

type Boat struct {  
  // embed the "superclass" as an unnamed struct member
  Vehicle
}

func (b Boat) Move() {  
  b.Vehicle.Move()
  println("boat moving")
}

func main() {  
  new(Boat).Move()
}

Interfaces

There is also no explicit declaration for implementing an interface. Instead, Go uses static "duck typing." This is not the official term, but it is quite a good description. We define interfaces, and any type can fulfill that interface simply by implementing the functions it defines. If it looks like a duck and quacks like a duck, it is a duck.

package main

type Quacker interface {  
  Quack()
}

type Duck struct{}

func (d Duck) Quack() {  
  println("duck: quack quack")
}

type Cat struct{}

func (c Cat) Quack() {  
  println("cat: quack quack")
}

func main() {  
  var q Quacker = new(Duck)
  q.Quack()
  q = new(Cat) // a cat *is* a Quacker
  q.Quack()
}

The Go standard library is filled with examples of this, and it works remarkably well. Interfaces are checked at compile time, so you have immediate feedback if a type doesn't fulfill the interface that you think it does. The example also shows another Go convention: interfaces that specify a single function are usually named after that function plus -er.

Concurrency

Go is designed with servers in mind. It's generic enough to perform well in many different environments, but servers are where it shines. Goroutines and channels make this possible. You can read some great explanations here, but I'll show you what they look like.

package main

func work(id int) {  
  println("processing top secret document:", id)
}

func main() {  
  for i := 0; i < 5; i++ {
    go work(i)
  }
}

This example won't actually do anything, because the main process will (most likely) exit before the goroutines have a chance to run. But it shows that running a task concurrently is as simple as prefixing the call with the go keyword. Goroutines are made much more helpful by using channels, which can be used to communicate between asynchronous tasks and to coordinate their efforts.

package main

func work(id int, done chan int) {  
  println("processing top secret document:", id)
  done <- id
}

func main() {  
  done := make(chan int, 5)
  for i := 0; i < 5; i++ {
    go work(i, done)
  }
  for i := 0; i < 5; i++ {
    id := <-done
    println("finished processing document:", id)
  }
  println("finished processing all documents")
}

The channel syntax done <- id pushes the value of id into the channel, to be read by a consumer at some later time. The second for loop reads values from the channel one at a time with id := <-done.

Go Tools

One of my favorite parts of using Go is the awesome set of tools that the developers built into the project. The go get command will recursively fetch source dependencies. Instead of building a centralized package repository like many other languages, (ruby gems, nodejs npm, etc.) Go source is identified by a simple URI. For example, go get can grab code from a git repository:

go get github.com/ha/doozerd

or a mercurial repository:

go get code.google.com/p/go.net/websocket

go fmt formats Go code. As a side effect this eliminates all debates on code style when writing in Go. go fmt has the last word.

go doc generates documentation from Go source files. It will also serve up a nice website with all the documentation over http. (the standard library documentation uses the same tool)

go test runs tests using Go's built-in testing and benchmarking library.

go install analyzes all dependencies directly from source and builds and links Go binaries. No need for a makefile or any other build system.

go run will transparently compile and then run a Go source file.

Other languages have these tools, but usually not directly from the language designer. And usually not implemented so well (read: simply).

Learning Go

The best place to start learning Go is the official Go Tour. I touched on some of the more interesting parts of Go in this post, but there is plenty more to learn. But not too much. Because of it's simplicity, Go is an incredibly easy language to learn. Take it from these guys:

I feel confident in saying that time from zero to productive commits is faster in Go than any other language we use; sometimes, dramatically so.

--Peter Bourgon, Soundcloud

Go’s true power comes from the fact that the language is small and the standard library is large. We’ve had developers start from zero experience with Go to writing working, production code in a day. That is why we’re so excited about its place in our stack.

--Matt Reiferson, Bitly

That said, it will take a bit longer to learn how to write idiomatic Go well, but there are resources for that as well. You will refer back to Effective Go many times. It explains how to write and understand idiomatic Go. The language spec is also easy to read and search. For anything else, you have Google, but use "golang" in searches.

Slides

Here are the slides from my presentation on 9/10/13:

Tags: programming, go, golang