Monthly Archives: January 2013

What is the zero value, and why is it useful?

Let’s start with the Go language spec on the zero value.

When memory is allocated to store a value, either through a declaration or a call of make or new, and no explicit initialization is provided, the memory is given a default initialization. Each element of such a value is set to the zero value for its type: false for booleans, 0 for integers, 0.0 for floats, "" for strings, and nil for pointers, functions, interfaces, slices, channels, and maps. This initialization is done recursively, so for instance each element of an array of structs will have its fields zeroed if no value is specified.

This property of always setting a value to a known default is important for safety and correctness of your program, but can also make your Go programs simpler and more compact. This is what Go programmers talk about when they say “give your structs a useful zero value”.

Here is an example using sync.Mutex, which is designed to be usable without explicit initialization. The sync.Mutex contains two unexported integer fields. Thanks to the zero value those fields will be set to will be set to 0 whenever a sync.Mutex is declared.

package main

import "sync"

type MyInt struct {
        mu sync.Mutex
        val int
}

func main() {
        var i MyInt

        // i.mu is usable without explicit initialisation.
        i.mu.Lock()      
        i.val++
        i.mu.Unlock()
}

Another example of a type with a useful zero value is bytes.Buffer. You can decare a bytes.Buffer and start Reading or Writeing without explicit initialisation. Note that io.Copy takes an io.Reader as its second argument so we need to pass a pointer to b.

package main

import "bytes"
import "io"
import "os"

func main() {
        var b bytes.Buffer
        b.Write([]byte("Hello world"))
        io.Copy(os.Stdout, &b)
}

A useful property of slices is their zero value is nil. This means you don’t need to explicitly make a slice, you can just declare it.

package main

import "fmt"
import "strings"

func main() {
        // s := make([]string, 0)
        // s := []string{}
        var s []string

        s = append(s, "Hello")
        s = append(s, "world")
        fmt.Println(strings.Join(s, " "))
}

Note: var s []string is similar to the two commented lines above it, but not identical. It is possible to detect the difference between a slice value that is nil and a slice value that has zero length. The following code will output false.

package main

import "fmt"
import "reflect"

func main() {
        var s1 = []string{}
        var s2 []string
        fmt.Println(reflect.DeepEqual(s1, s2))
}

A surprising, but useful, property of nil pointers is you can call methods on types that have a nil value. This can be used to provide default values simply.

package main

import "fmt"

type Config struct {
        path string
}

func (c *Config) Path() string {
        if c == nil {
                return "/usr/home"
        }
        return c.path
}

func main() {
        var c1 *Config
        var c2 = &Config{
                path: "/export",
        }
        fmt.Println(c1.Path(), c2.Path())
}

With thanks to Jan MerclDoug LandauerStefan Nilsson, and Roger Peppe from the wonderful Go+ community for their feedback and suggestions.

Using screen for lazy dot files

I have a lot of shell accounts; on my laptops and workstations, on my ARM build boxes, on remote servers, and so on. I don’t make a lot of customisations to my login shell as the lowest common denominator of OS X, FreeBSD and various Linux distros has trained me to live with what is on the host.

I do have two exceptions, bash and screen1. Handling my screen config is easy; just scp my .screenrc file to the new host. Handling the small number of changes to my bash setup is more involved as bash has several places it looks in (.bashrc, .bash_profile, sometimes just .profile) and those files may already exist on the host.

Recently I’ve been experimenting with the idea of using screen to handle this customisation, which reduces the amount of configuration data copied to a new host to a single new file. Here is a sample .screenrc from an ARM FreeBSD build box.

startup_message off
vbell off

# Window list at the bottom.
hardstatus alwayslastline "%{wk}%-w%{Gk}[%n %t]%{wk}%+w%=%{Ck}%M%d %c%{-} %{=r} ${USER}@%H"

# who needs .bashrc ?
shell bash
setenv PS1 "\[\e]0;\u@\h: \w\a\]\h(\w) % "
setenv GOROOT /u/go                           
setenv GOPATH $HOME
# yup, screen can expand shell vars
setenv PATH $PATH:$GOROOT/bin:$GOPATH/bin 

autodetach on
term xterm-color
termcapinfo xterm ti@:te@

Combined with ssh $HOST -t -- screen -R -D, this makes setting up a new machine very simple.


1. Note to haters. I know that alternatives like zsh and tmux exist, but neither are installed by default on any mainstream distro, so until they are, I don’t care. At any rate, these suggestions probably apply equally well to your chosen shell and screen multiplexer.

Go, the language for emulators

So, I hear you like emulators. It turns out that Go is a great language for writing retro-computing emulators. Here are the ones that I have tried so far:

trs80 by Lawrence Kesteloot

I really liked this one because it avoids the quagmire of OpenGL or SDL dependencies and runs in your web browser. I had a little trouble getting it going so if you run into problems remember to execute the trs80 command in the source directory itself. If you’ve used go get github.com/lkesteloot/trs80 then it will be $GOPATH/src/github.com/lkesteloot/trs80.

trs80

GoSpeccy by Andrea Fazzi

GoSpeccy was the first emulator written in Go that I am aware of, Andrea has been quietly hacking away well before Go hit 1.0. I’ve even been able to get GoSpeccy running on a Raspberry Pi, X forwarded back to my laptop. Here is a screenshot running the Fire104b intro by Andrew Gerrand

GoSpeccy on a Raspberry Pi

Fergulator by Scott Ferguson

Like GoSpeccy, Fergulator shows the power of Go as a language for writing complex emulators, and the power of go get to handle packages with complex dependencies. Here are the two commands that took me from having no NES emulation on my laptop, to full NES emulation on my laptop.

lucky(~) sudo apt-get install libsdl1.2-dev libsdl-gfx1.2-dev libsdl-image1.2-dev libglew1.6-dev libxrandr-dev
lucky(~) % go get github.com/scottferg/Fergulator
Fergulator

sms by Andrea Fazzi

What’s this? Another emulator for Andrea Fazzi ? Why, yes it is. Again, super easy to install with go get -v github.com/remogatto/sms. Sadly there are no sample roms included with sms due to copyright restrictions, so no screenshot. Update: Andrea has included an open source ROM so we can have a screenshot.

sms

Update: Several Gophers from the wonderful Go+ community commented that there are still more emulators that I haven’t mentioned.