• An Introduction to Google’s Go Programming Language

By Melissa Soriano

Go is Google’s new open-source, compiled programming language.  It’s release was officially announced in November of 2009.   I spent a few hours getting my feet wet with Go and exploring how it compares to C and Python.  This article describes how to install Go, how to compile a program, and some of Go’s unique features.

Installing Go

Go implementations are currently available for the Linux and Mac OS X platforms.
The following environmental variables are required and should be added to your ~/.bashrc or ~/.profile:

export GOROOT=$HOME/go export GOBIN=$HOME/bin export GOOS=linux export GOARCH=386 PATH=$GOBIN:$PATH

In order to build the go toolchain, you need gcc, the standard C libraries, the parser generator Bison, make, awk, and the text editor ed installed.  You will also need mercurial, a free distributed source control management tool.  Once you have all this, you can check out the Go Mercurial repository:

$ hg clone -r release https://go.googlecode.com/hg/ $GOROOT

Building go:

$ cd $GOROOT/src $ ./all.bash

At the end of the build, you should see:
— cd ../test
N known bugs; 0 unexpected bugs

Compilation and Linking

Go includes a suite of compilers for different architectures.  8g is the compiler for the 32-bit x86.  6g is the compiler for the 64-bit x86.  For example, below is a simple hello.go program and its compilation:

package main import "fmt" func main() { fmt.Printf("hello, world\n") }

To compile on a 32-bit x86 platform:

8g hello.go

This will produce a file named hello.8.  To link the file:

8l hello.8

This will produce a file named 8.out.  To run it:

./8.out

Coding in Go

In general, Go code looks a lot cleaner than C or Python.  Go doesn’t have the same sensitivity to white space that Python does (which can be a pro or a con depending on your point of view).  Like C, Go uses semicolons to terminate statements but unlike C, the compiler puts these in automatically, resulting in cleaner source files.  Go’s compiler is very strict about dependencies; it returns errors for any package or variable that is not used.  This results in cleaner code with fewer dependencies, but can be annoying during initial development.  I tend to use the compiler as a tool and I compile often when I develop in C.  Go makes this harder by complaining about every loose end.  I wish it were possible to turn this dependency checking on and off (for example with a -strict flag) but I think Go’s designers made this choice on purpose as part of their philosophy that the language’s design should promote good programming practices.  This dependency checking might be something I would get used to if I worked with Go more.

As an example, I wrote a simple program that reads from an input file and writes to an output file.  I used the io/ioutil package, which provides ReadFile and WriteFile functions and the fmt package, which provides Printf.  Documentation of Go’s libraries can be found at http://golang.org/pkg/. All packages on this Web site are searchable using the “Go Code Search” box in the menu on the left hand side.

File IO in Go Example
Download file.go here

/* This example reads data from an input file, prints the data to the screen, and writes the data to an output file. */ package main import ( "fmt" "io/ioutil" ) func main() { /* declare input and output filenames */ input_filename := "data.txt" output_filename := "stats.txt" /* read contents of input file into array of type byte */ buff,_ := ioutil.ReadFile(input_filename) /* print contents of input file */ fmt.Printf("%s\n", string(buff)) /* write contents of buff to output file */ /* use permissions 0x644 */ ioutil.WriteFile(output_ filename, buff, 0x644) }

The brevity of the code and the lack of semicolons result in a clean, compact source.  The := operator represents a variable declaration.  Like python, Go can figure out the type of the variable implicitly based on the value you use to initialize it.  This feature speeds up initial development and makes the language friendly to work with.  Another feature of Go that I really like is its ability to returns multiple values.  This is demonstrated by ReadFile, which returns an array of type byte (buff), and an error code.  In C, I often write functions that need to return a value (for example, how many lines were read) that also may need to return an error.  This leads to the inelegant solution of defining a particular return value to signify an error (for example, -1).  While this solution works, it relies on the requirement that valid return values have a limited range (for example, >=0).  Another solution is to create a structure that contains multiple members with the information that is needed and to have the function return this structure.  Again, this works, but it is cumbersome and may end up requiring you to twist yourself around, defining all sorts of new structures just to enable a function to return the values that you need.  A third solution is to pass in a variable by reference and modify it within the function.  This works but obfuscates the function’s purpose.  Go’s ability to return multiple values provides a simple, elegant solution.  One weakness of Go seems to be its parsing abilities.  I used ReadFile to read an ascii text file of letters and numbers into an array of bytes, which ended up being difficult to work with.  I miss C’s fscanf and python’s readln and split functions.  Go’s novelty also means that far less example code is available than is the case for C and Python.  It would be nice if the documentation for each package included examples.  If Go becomes accepted by the software development community, this may change and more resources may develop.

As another example, I wrote a simple generic sort function that utilizes Interfaces and used this function to sort floats and strings.

Sorting in Go Example
Download sort.go

/* This example sorts arrays of strings and floats */ package main import ( "fmt" "rand" "time" ) /* define an Interface for an array of floats */ type FloatArray []float func (p FloatArray) Len() int {return len(p)} func (p FloatArray) Less(i int, j int) bool {return p[i] < p[j]} func (p FloatArray) Swap(i int, j int) {p[i], p[j] = p[j], p[i]} func (p FloatArray) List() string { s := "{ " for i:=0; i< p.Len(); i++{ s += fmt.Sprintf("%3.1f ", p[i]) } s += "}" return s } func (p FloatArray) String() string { return p.List() } /* fill 1-n members of p with randomly generated floats between 0-100 */ func (p FloatArray) Fill(n int) { rand.Seed(time.Nanoseconds()) for i:=0; i< n; i++{ p[i] = 100*(rand.Float()) } } /* define an Interface for an array of strings */ type StringArray []string func (p StringArray) Len() int {return len(p)} func (p StringArray) Less(i int, j int) bool {return p[i] < p[j]} func (p StringArray) Swap(i int, j int) {p[i], p[j] = p[j], p[i]} func (p StringArray) List() string { s := "{ " for i:=0; i< p.Len(); i++{ s += fmt.Sprintf("%s ", p[i]) } s += "}" return s } func (p StringArray) String() string { return p.List() } /* Generic Interface to any sortable type */ type Interface interface { Len() int Less(i, j int) bool Swap(i, j int) } /* generic sort function */ func Sort(data Interface) { for i := 1; i < data.Len(); i++ { for j := i; j > 0 && data.Less(j, j-1); j-- { data.Swap(j, j-1) } } } func main() { numbers := FloatArray{44.5, 67.3, 3.9, 17.8, 89.0, 10.2, 76.3, 9.4, 14.7, 89.1} strings := StringArray{"kobe", "odom", "farmar", "fisher", "artest", "bynum", "brown", "gasol"} Sort(numbers) fmt.Printf("%v\n", numbers) numbers.Fill(10) Sort(numbers) fmt.Printf("%v\n", numbers) Sort(strings) fmt.Printf("%v\n", strings) }

Running the program:

soriano@home:~/go/src$ ./8.out { 3.9 9.4 10.2 14.7 17.8 44.5 67.3 76.3 89.0 89.1 } { 11.2 27.8 36.0 49.1 73.2 86.3 88.5 94.1 98.2 99.0 } { artest brown bynum farmar fisher gasol kobe odom }

This example illustrates Interfaces, which are a feature unique to Go.  The generic sort function is defined using Len, Less, and Swap sub-functions.  The sort function can then be used by any type that defines Len, Less, Swap, and additionally List methods that are specific to that particular type.  For example, arrays of both floats and strings may be sorted and methods were defined to allow these types to utilize the generic sort function.  The sort function is dynamic because the usage of the sort function determines the type of the data variable.  At the same time, the individual Interfaces are parsed by the compiler, which prevents runtime errors as may occur in Python.  I added String methods to both types.  When Printf is called, it automatically checks to see if a String method is defined for the type and if so, uses it, as demonstrated above.

C, Python, and other languages provide support for concurrent programming in the form of processes and threads.  Go implements this using goroutines.  A goroutine is a Go function or method that executes concurrently in the same address space as other
goroutines.  Any function may be run as a goroutine by simply prefacing it’s call with “go”.  I write a simple example with two goroutines that run at the same time, in the same address space, and receive messages from the main program.

Goroutines Concurrency Example
Download goroutines.go

/* This example demonstrates usage of goroutines */ package main import ( "fmt" "time" ) func handler(label string, mychan chan string) { var message string for i := 0; i < 10; i++ { /* receive message from channel */ message = <-mychan; fmt.Printf("%s: %s\n", label, message); time.Sleep(100); } } func main() { /* allocate a new channel */ msgchan := make(chan string) /* concurrent goroutines */ go handler("goroutine1", msgchan); go handler("goroutine2", msgchan); /* send messages */ msgchan <- "when" msgchan <- "in" msgchan <- "the" msgchan <- "course" msgchan <- "of" msgchan <- "human" msgchan <- "events" msgchan <- "it" msgchan <- "becomes" msgchan <- "necessary" msgchan <- "for" msgchan <- "one" msgchan <- "people" /* let main sleep */ time.Sleep(1000) }

Running the program:

soriano@home:~/go/src$ ./8.out goroutine1: when goroutine2: in goroutine2: the goroutine1: course goroutine1: of goroutine2: human goroutine1: events goroutine2: it goroutine1: becomes goroutine2: necessary goroutine1: for goroutine2: one goroutine1: people

In this example, a handler function is implemented that accepts a label identifier and a channel as arguments.  A channel is a new Go type that is used to communicate between goroutines.  In this case, we declare “mychan chan string” which is a channel of type string called mychan.  This channel is used by the function to receive a message (message = <-mychan) and display it.  In main, a channel named msgchan is allocated and two handler goroutines are declared.  Messages are then sent using the channel.  By default, a send operation on a channel blocks until a receiver is available.  Therefore the first message is sent on the msgchan channel, and main blocks until either goroutine1 or goroutine2 receives it.  In this case, goroutine1 receives and sleeps for 100 nanoseconds.  In the meantime, main sends the next message on the msgchan channel and blocks again until it is received.  In this case, goroutine1 is still sleeping, so goroutine2 receives the second message and then sleeps for 100 nanoseconds.  Main sends the third message and goroutine2 is awake so it receives.  The channel makes it easy to communicate and synchronize between the two processes.  This example is a simple one but it demonstrates the simplicity and power of goroutines.  The Go approach to concurrency is significantly different from C and Python’s processes and threads and motivate a new way of thinking.  Of course, this is just the beginning.  Goroutines have a lot of potential and this is one of Go’s unique features that I would definitely like to explore further.

Thoughts

At first glance, Go is intriguing.  It includes some new innovative features that other languages such as C and Python lack, such Interfaces and goroutines.  Go code is also clean and quick to compile.  Go was designed with concurrency in mind; goroutines and channels have a lot of potential because pretty much any new computer has multiple cores and its is powerful to be able to take advantage of this parallel processing ability.  However, as with any language, there is a bit of a learning curve and since it Go is new, it lacks the established community and code base of other more established languages.  I did enjoy playing with Go and exploring its possibilities and I may consider using it for my next project.

More Resources

Go Video Introduction

Official Go Tutorial

Go is the property of Golang.org and used in compliance with the Creative Commons Attribution 3.0 License.
Google is the respective trademark of Google, Inc.
Share and Enjoy:
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • DZone
  • E-mail this story to a friend!
  • FriendFeed
  • HackerNews
  • LinkedIn
  • Reddit
  • StumbleUpon
  • Suggest to Techmeme via Twitter
  • Technorati
  • Twitter
  • FSDaily
  • Ping.fm

This website uses IntenseDebate comments, but they are not currently loaded because either your browser doesn't support JavaScript, or they didn't load fast enough.

  1. Tweets that mention An Introduction to Google’s Go Programming Language #rss #articles #softwareengineering -- Topsy.com Says:

    [...] This post was mentioned on Twitter by The Bitsource, Matthew Sacks and kicauan, Thomas Buck. Thomas Buck said: An Introduction to Google's Go Programming Language http://www.thebitsource.com/articles/google-go-programming-introduction/ [...]

  2. Says:

    [...] This post was mentioned on Twitter by The Bitsource, John James Tysoe. John James Tysoe said: An Introduction to Google's Go Programming Language – http://bit.ly/aqEfRU [...]

Leave a Reply

You must be logged in to post a comment.