Golang interfaces, a pragmatic explanation for the programmer

I’m still in the process of learning golang the right way. Yes I already wrote some projects with the _Go_ language (here and here), but I like to understand the real meaning of techniques when using them.
One of what is said to be the most amazing features of _Go_ is interfaces. Here’s what the official golang docs has to say about it:

Interfaces in Go provide a way to specify the behavior of an object: if something can do this, then it can be used here. We’ve seen a couple of simple examples already; custom printers can be implemented by a String method while Fprintf can generate output to anything with a Write method. Interfaces with only one or two methods are common in Go code, and are usually given a name derived from the method, such as io.Writer for something that implements Write.

Am I just stupid? Did you actually understand this sentence at first sight? I didn’t. Maybe my english is not good enough. Let’s try another one:

An interface type is defined by a set of methods. A value of interface type can hold any value that implements those methods.

Ok… this one maybe?

An interface type is defined as a set of method signatures. A value of interface type can hold any value that implements those methods.

To be honest, I kind of got it, but why does every tutorial needs to back a hardly understandable definition with absolutely unnatural examples for us programmers? Animal interface with Dog and Cat types? Singer? Humans? Is that the kind of programs you write?

So I finally came up with a “real life” example that helped me out understand both interfaces capabilities:

  • (the second capability will come later) An interface can be used for genericity, functions declared in an interface type can be mapped to methods so there’s one single name that will do the same kind of operation but using different techniques. I will use an example that we might all understand:

We programmers often have to deal with format conversions, i.e. read the content of a file and then extract its actual data. Let’s imagine you’re working on a project which chose to switch from xml configuration files to json format (yay!). You might want to write a generic call to handle both situations the same way, and this is where an interface can be very convenient. Let’s have a look at what it might look like:

First let’s declare the actual interface generic type

1
2
3
type Map interface {
Unmarsh() map[string][]int
}

Yeah, there’s no need to specify the func keyword here to declare functions as there can only be this type here. So we declare the Unmarsh() function which will -for now- return a map suited for this kind of data: {"foo": [1, 2, 3]}

Then we declare two raw types

1
2
3
4
5
6
7
type Json struct {
input []byte
}

type Xml struct {
input []byte
}

Let’s create a dummy structure to receive decoded xml, nothing related to the interface explanation:

1
2
3
4
type Xmlout struct {
Name string `xml:"name,attr"`
Item []int `xml:"item"`
}

Now the real deal, we will write two methods one for each type, Json and Xml.
But wait, something won’t behave as we would like: in our project, json and xml Unmarshal functions don’t act the same, json.Unmarshal() fills a map, while xml.Unmarshal() fills a struct. This means our “generic” Unmarsh() call can’t return the same type of data.
Actually, json.Unmarshal() knows how to fill a struct, but for the sake of this demonstration, let’s just assume we decided that our project would be far simpler by just using a map.
I’ll use this scenario to demonstrate the second useful usage of interfaces:

  • When no methods are implemented, interface{} can be used as an untyped, generic data receiver. I like to see it as a form of C’s void *.

And here’s how it can be simply used:

1
2
3
type Map interface {
Unmarsh() interface{}
}

That’s right, simply replace the return type with an empty interface and the function can now return whatever type wanted.

As we’re no more bothered by the return type, we can write both Unmarsh() methods:

1
2
3
4
5
6
7
8
9
10
11
func (js Json) Unmarsh() interface{} {
m := make(map[string][]int)
json.Unmarshal(js.input, &m)
return m
}

func (x Xml) Unmarsh() interface{} {
var xo Xmlout
xml.Unmarshal(x.input, &xo)
return xo
}

As you can see, those two method use different techniques to Unmarshal() data located in the input field of the struct, nevertheless, we will now see how this call can be leveraged:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
func main() {

var t Map

t = Json{[]byte(`{"x": [1, 2, 3]}`)}

fmt.Println(t.Unmarsh())

t = Xml{[]byte(`
<list name="x">
<item>1</item>
<item>2</item>
<item>3</item>
</list>
`)}

fmt.Println(t.Unmarsh())
}

The trick here is that the data receiver is a Map typed (the interface one) variable named t, the interface will then transparently do its magic in order to pick the right struct and associated method based on the passed parameter type. Here I found a pretty good explanation of the implementation of such wizardry.

Witness the output of this example:

1
2
map[x:[1 2 3]]
{x [1 2 3]}

That’s right, one call to rule them all. Now obviously this is not the final result you would want to see and you’d probably transform the latter to a map pretty easily, but now hopefully you understand both usages of _Go_’s interfaces!