The Go Programming Language
Posted: 2013-03-15
I am always on the look out for new programming languages. It is my vain hope that some day a language will be developed that will distil all the lessons we have learned about programming language design so far and will unlock new highs of productivity and creativity. In my opinion, the ‘Go’ programming language is a very good attempt at doing this for system engineering.
Background
Go is just 3 years old and only recently achieved its first stable milestone release, version 1.0.0, in March 2012. It has been designed and built internally at Google by Rob Pike and Ken Thompson (both known for the Plan9 operating system, UTF-8 and Unix), Robert Griesemer (who worked on Strongtalk and the Hotspot JVM), and others. Their remit was to design a language that could scale to cope with the huge number of interconnected systems, users, engineers, and lines of code that Google needs to deal with day to day.
So what does it look like then?
It is a statically typed, garbage collected language that sits at the level somewhere between C/C++ and Java/C#, and compiles down to platform native code.
Although it has a C-like syntax, it also includes high-level features like built-in dictionary/map support similar to scripting languages like JavaScript or Python, and function closures like JavaScript.
Here’s an example, taken from Rob Pike’s “Go Concurrency Patterns” talk, that demonstrates several important features:
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
// A function returning a channel
c := boring("boring!")
for i := 0; i < 5; i++ {
// Read a string from the channel and print it
fmt.Printf("You say: %q\n", <-c)
}
fmt.Println("You're boring; I'm leaving.")
}
// A generator function that returns a receive-only channel of strings.
func boring(msg string) <-chan string {
// Create the channel of strings
c := make(chan string)
// Define an anonymous function and run it as a goroutine
go func() {
for i := 0; ; i++ {
// Send a message to the channel
c <- fmt.Sprintf("%s %d", msg, i)
time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond)
}
}()
// Return the channel to the caller
return c
}
I’ll leave it to Rob to explain what’s going on here in detail. Admittedly, this may be a little challenging to understand if you are not already familiar with the basics of the language. For a quick step-by-step introduction take the tour.
Probably the most important feature is its support for parallelism and concurrency. For this, Go’s designers refer to ideas from a 1978 paper (really has it take us the length of my entire lifetime to get here?) by Tony Hoare called “Communicating Sequential Processes”. These are realised in Go by goroutines, which are concurrent processes that communicate with each other by sending messages over channels. The idea is, by coordinating through message passing, rather than shared memory, it enables lock-free programming.
What I like about it so far
I have only been investigating it for a few weeks, and haven’t built anything significant with it yet. However, there are already a number of features that appeal to me. I had intended to keep this list small, but to hell with it, there are a lot of things I like about it already :-) here we go:
- It has a C-like syntax, but its terser. Semi-colons are not required, braces around for and if statements are dropped, and if variables are assigned where they are declared you can drop the type specification.
- Capitalisation of names is used to control public/private access, which eliminates a lot of extra syntax.
- It has borrowed some conveniences from Python: array slices, a built-in map type, and functions can return multiple values.
- It has first class functions, which are full closures. Enabling a tonne of great programming paradigms that are in common use in languages like JavaScript and Ruby.
- It is sort-of object oriented, but more like the way C is, in that objects are declared as structures with methods defined outside of the structure declaration. It does not support inheritance. Instead it provides a mixin-likestyle of extension, known as embedding, where new types can be created by mixing together existing types or interfaces to produce a type which is a union of the features of the types it combines.
- It supports the concept of interfaces like C++/Java/C#, but with additional flexibility because it follows a sort of static version of the duck typing idiom: any object can implement an interface simply by defining functions that match the signatures declared in that interface. There is no need to explicitly declare that an object implements an interface. The benefit this brings is that it makes it possible to write polymorphic code without requiring the individual types involved to have been pre-designed for use in this way.
- You can create new types from anything, even an int, and can then add methods to your new type.
- It has a well thought out declaration syntax, with intent of straightening out the complicated C declaration rules to produce something that is easier to parse by eye or machine.
- They fixed the switch statement (hurray!) so that cases break by default, and enhanced it so that any type can be the switch condition. Plus, there is a switch with no condition, which has an implicit condition that defaults to true, and provides a compact replacements for long if-else chains.
- It has a logically named set of basic types, including C
<stdint.h>
style explicit precision versions:bool
,int
,int8
,int16
,int32
,int64
,uint
,uint8
, and so on. - It has a built-in unicode string type.
- It supports pointers for those times when you need to pass by reference instead of passing by value. However, pointer arithmetic is not supported.
- It compiles to platform native binary formats. So no messing around with byte code interpretors or class paths required to run an application. In fact, I had a quick look at what DLLs a simple ‘hello world’ style Go binary links with on Windows: only
kernel32.dll
andwinmm.dll
for a multimedia timer API. On Linux there are no dynamically linked dependencies at all. So the resulting binaries don’t require the user to install a Go runtime, which makes them refreshingly portable. - It has a garbage collector, so you don’t have to worry about the large majority of memory leak issues that you have to in C.
Oh, it also has a cute mascot called the ‘Gopher’ [see the image above] :-)
Toolchain and workflow
What is also excellent about Go is that the tool-chain has not been left an after-thought.
It comes bundled with more than just a compiler, so there is no need to mess around with makefiles!! :) This makes it very easy to get up and running.
The main way of building Go source code is by using the go front-end command-line tool. It has a simple Git/Subversion inspired interface, with sub-commands for building, installing, testing, formatting, and various other tasks.
It also has a run
sub-command that builds and runs in one step. Impressively, because the compiler is fast enough, this means that Go can be used almost as if it is a scripting language. A simple idea really, but a nice touch that makes it so easy to code up small experiments and small tasks. I have often created shell scripts to do the same in C when trying to hack out a small idea quickly.
As far as I can tell at the moment, there are two main schemes for source organisation:
- All project sources in one directory - for example the
go
command sources are organised like this (see$(GOROOT)/src/cmd/go
in your installation). Typically, twenty to thirty source files all in one directory along with any scripts and README files etc. - Sources organised into a directory hierarchy of packages called a Go workspace. Each package sub-directory may be a separate project or source repository.
Interestingly, it appears there is no middle ground here: if you take the first scheme and try to organise some of your code into packages in sub-directories, the compiler just cannot find the nested sources. Granted, there may be a way around this but I need to dig deeper (please tell me if I’m wrong). Anyway, for more on this topic see: here.
What types of tasks is it good for?
At the moment it appears to be targeted at writing network and system services. But, I guess this may expand in time. Here’s a big list of projects written in Go.
SoundCloud are using it to write back-end systems.
Further reading
Here are some other interesting sources of information:
- The project home page http://golang.org/.
- The Go Tour - an interactive online tutorial
- The Design FAQ
- Effective Go
- Calling Go from Python via JSON-RPC by Bruce Eckel