jLuger.de - The Go Programming Language

In this post I want to share the experience I've made when learning go and realizing a small project. This is not a tutorial for the language. If you are looking for that go over to http://golang.org/doc/docs.html and work yourself through the material. You haven't heard of Go and want to know what it is?

Go is a programming language started by Google employees. Two of them were Rob Pike and Ken Thompson. The Ken Thompson that is one of the fathers of UNIX. Rob Pike is known for working on the Plan 9 operating system. Some big names in IT. Besides these two and other Google employees there are now also individuals from outside that add to the development of the language. What's also in it? It has I've heard of Go some time ago when it was called stable but I've just started to consider it as a language to use after I had read an article in the 18th issue of c't from 18.11.2011 (German date format). Then there was this unfinished C project that should deduplicate mails. I needed to get some runtime support like message digests and maps for it which Go has out of the box. So I've decided to port the created code to Go and implement the rest there.

Before I dive into Go I need to state a warning. Go and the supporting tools are under active development. This causes documentation to get really fast obsolete. When searching for a certain feature and you read that it isn't implemented yet better check the date of the message. It may have been implemented in the mean time. Although some criticism or workarounds I show here may be no longer true/needed in the near future as I will not update the post to keep up with the development of Go.

To start with Go you need to install it. Go requires a C build chain, a Mercurial client, and a supported OS. I've named supported OS as the windows support is a little bit unclear. Some documents call it unstable while others say it is
finished. When you use Linux you are out of this trouble. For the other tools/steps see http://golang.org/doc/install.html. Just ensure that you set all the environment variables correctly that are mentioned on the install site. For the sake of completeness I have to mention that the gcc also supports Go but it is turned off by default. This means that you have to compile gcc by yourself in order to get it.

To get IDE support for programming in Go go to http://code.google.com/p/goclipse/. This is an Eclipse plugin. Currently this plugin relies on http://github.com/nsf/gocode for autocompletion. After downloading and compiling it, make sure that it is installed into the go folder (the gocode program must be in the same bin folder where the Go compiler is). First the autocompletion didn't work. I don't know for sure but I guess it is because I've started the gocode server by hand. According to http://code.google.com/p/goclipse/wiki/GocodeIntegration this is necessary. But autocompletion started working when I didn't start gocode by myself.

When the compiler and the IDE are setup the next step is to create a Project in Eclipse. The new project will have two source folders: cmd and pkg. Place all files that should create executables in the cmd folder. pkg seems to be for libraries.

After the obligatory hello world program I've started to search for interfacing with C libraries. There is the tool cgo that will allow you to do that. The bad news is that the Eclipse plugin doesn't support cgo. It will show an error marker on the import "C" statement for cgo. In order to get a package that could be used by my main program I had to create a Makefile (see http://blog.golang.org/2011/03/c-go-cgo.html for an example). The Makefile needs to be placed in the same directory where the source file is. I've tried to place it in a parent directory. Compiling failed. When you search for other C-Bindings using cgo you will see that they all place the Makefile in the same directory where their code is. Another point is that the install target has to be called. This will make the package available in the go installation. You may don't want to have it available to all applications but I have found no other way. I don't think that gocode will recognize application private libs and offer autocompletion for them. Another drawback of this solution is that you need to make fake edits to the program when you have recompiled the library and want to see the results in it.

In order to get a feeling about how to interface with C libraries you should browse through existing bindings at http://go-lang.cat-v.org/library-bindings. While doing this keep in mind that almost all function names after C. are C methods defined in a library. The part "defined in a library" is very important. When you look at functions defined in a header file ensure that they get compiled as functions and aren't just some macro definitions somewhere else. You should also note that you don't write C.NULL but have to use Gos nil and that there is no -> operator but the . could be used in most cases. I think there was once an issue where I had to deal with pointer of pointer. There I needed to dereference that first pointer and put brackets around it.

When getting lists of data you want to save them. If you start searching the package documentation you will get to http://golang.org/pkg/container/list/. This is double linked list. Retrieving data from the list reveals that Go doesn't have Generic and that you have to use duck typing to get the elements. Assume l is a list filled with strings. Then
first := l.Front()
first.Value.(string)
will get the the first element of the list as string. Note that := is a define and assign operator.

This list handling seems to be pretty unsafe but the good news is that Go has dynamic growing arrays called slices. They are defined with a type and thus type safe. There is also a built-in map that is type safe too. So Generics aren't missed that much.

In order to cast one value to another, e.g. an int to a byte, you write byte(i) where i is an int value. That is the general format for casting values in Go. But when it comes to pointer you have to go back to the old C cast style: (*C.struct_mailimf_mailbox)(unsafe.Pointer(voidPointer)).

One of the greatest features I've used (there is at least another one I didn't use for my mail application) is the defer keyword. You write it before a function call and then this function call won't be executed at this place but when the function returns to the caller. Say you call function B from function A. In function B you open a connection to a remote server. Now you have to close the connection before returning to function A. With the help of defer you can place the call right after the open statement (better after you've checked that the connection is established). The connection will be closed on return to A. No matter how many return statements you place in B afterwards.

I wish there would be something similar for C but according to this document http://research.swtch.com/2010/03/broken-abstractions-in-go.html it is implemented with an assembler trick that isn't possible in plain C. The crazy thing is that this trick is pretty old. The early UNIX developer (hello Ken) used it already. It's that a pity that the trick got lost.

When using defer keep in mind that it is executed at the end of the function. When you allocate resources in a loop you shouldn't use it. Well, Go has lambda functions in which defer will work again. So either don't use defer or use lambda functions in loops.

Now, after I've written about what Go has I want to go to what Go doesn't have. First there are no Annotations that allow to add in a type safe manner extra information for the reflection (which Go has). On the other side this isn't a problem currently.

That's because the areas where you would like to use them (at least in Java) aren't supported by the runtime system. Yes, there are no Webservices, GUIs, or Database systems. You can create a Webserver or send mail but as soon as you wont to save the data or access the mails you're out of the scope of the default runtime system. To be fair I have to mention that there are bindings to C libraries for DB access and when you develop for the Googel App Engine they provide packages for the BigTable access too.

The Eclipse plugin is also missing features. Besides error marking and autocompletion you have almost nothing. No Code Browsing, no Refactoring, no autointention when you move code, and autocompletion won't work when the start text violates cases (you start typing lower case but the name is starting upper case).

Another bad point is that the Go compiler can only create static binaries. You can't split Go programs into a main program and shared libraries. This isn't an issue when you need to separate programs in an app engine but for real world programs it is cumbersome.

As a conclusion I can say that programming in Go is nice and beside the basic IDE support it is a pleasure to program in it but the runtime support is tailored to web and system programming as it is needed by Google. It is missing the kind of runtime support that would make it a good suite for general purpose programming. I hope that this will change in the future.