Go: Understand the Empty Interface

Vincent Blanchon
Aug 13, 2019 · 4 min read
Illustration created for “A Journey With Go”, made from the original Go Gopher, created by Renee French.

An empty interface can be used to hold any data and it can be a useful parameter since it can work with any type. To understand how an empty interface works and how it can hold any type, we should first understand the concept behind the name.

Interfaces

Here is a good definition of the empty interface by Jordan Oreilli:

An interface is two things: it is a set of methods, but it is also a type.

The interface{} type is the interface that has no methods. Since there is no implements keyword, all types implement at least zero methods, and satisfying an interface is done automatically, all types satisfy the empty interface

A method with an empty interface as argument can therefore accept any type. Go will proceed to a conversion to an interface type to serve this function.

Russ Cox made a great article about the internal representation of the interfaces and explains that an interface is composed of two words:

  • a pointer to information about the type stored
  • a pointer to the associated data

Here is a representation by Russ in 2009 when runtime was written in C:

The runtime is now written in Go but the representation is still the same. We can verify that with printing the empty interface:

(0x10591e0,0x10be5c6)

Both addresses represent the two pointers to type information and the value.

Underlying structure

The underlying representation of the empty interface is documented in the reflection package:

type emptyInterface struct {
typ *rtype // word 1 with type description
word unsafe.Pointer // word 2 with the value
}

As explained before, we clearly see that the empty interface has a type description word followed by the word that contains the data.

The rtype struct contains the base of the type description:

type rtype struct {
size uintptr
ptrdata uintptr
hash uint32
tflag tflag
align uint8
fieldAlign uint8
kind uint8
alg *typeAlg
gcdata *byte
str nameOff
ptrToThis typeOff
}

Among those fields, some are quite simple and well known:

  • size is the size in bytes
  • kind contains the type: int8, int16, bool, etc.
  • align is the alignment of variable with this type

Depending on the type embedded by the empty interface, we could map the exported fields or list the methods:

type structType struct {
rtype
pkgPath name
fields []structField
}

The struct has two more mappings including the list of fields. It clearly shows that converting a built-in type into an empty interface will lead to a flat conversion where the description of the field and its value will be stored in memory.

Here is a representation of the empty interface we have seen:

interface is composed by two words

Let’s now see what kinds of conversion are actually possible from the empty interface.

Conversions

Let’s try a simple program that uses the empty interface with a wrong conversion:

Although the conversion from int8 to a int16 is valid, the program will panic:

panic: interface conversion: interface {} is int8, not int16

goroutine 1 [running]:
main.read(0x10592e0, 0x10be5c1)
main.go:10 +0x7d
main.main()
main.go:5 +0x39
exit status 2

Let’s generate the asm code in order to see what check is done by Go:

code generated while checking the type of an empty interface

Here are the different steps:

  • step 1: compare (instruction CMPQ) the type int16 (loaded with the instruction LEAQ, Load Effective Address) to the inner type of the empty interface (instruction MOVQ that reads the memory with an offset of 48 bytes from the memory segment of the empty interface)
  • step 2: JNE instruction, Jump if Not Equal, will jump to the generated instructions that will handle the error in step 3
  • step 3: the code will panic and generates the error message we have previously seen
  • step 4: this is the end of the error instructions. This specific instruction is referred by the error message that shows the instruction: main.go:10 +0x7d

Any conversion from the inner type of an empty interface should be done after the conversion of the original type. This conversion to an empty interface and then to the original type back has a cost for your program. Let’s run some benchmarks to get a rough idea of it.

Performance

Here are two benchmarks. One with the copy of a struct and another one with the usage of an empty interface:

Here are the results:

BenchmarkWithType-8               300000000           4.24 ns/op
BenchmarkWithEmptyInterface-8 20000000 60.4 ns/op

It takes 55 more nanoseconds for the double conversion type to empty interface and then to the type back than copying the structure. The time will increase if the number of fields in the structure increases:

BenchmarkWithType-8             100000000         17 ns/op
BenchmarkWithEmptyInterface-8 10000000 153 ns/op

However, a good solution would be to use pointer and convert back to this same struct pointer. The conversion would look like this:

The results are now quite different:

BenchmarkWithType-8                 2000000000          2.16 ns/op
BenchmarkWithEmptyInterface-8 2000000000 2.02 ns/op

Regarding the basics type like int or string, the performances are slightly different:

BenchmarkWithTypeInt-8              2000000000          1.42 ns/op
BenchmarkWithEmptyInterfaceInt-8 1000000000 2.02 ns/op
BenchmarkWithTypeString-8 1000000000 2.19 ns/op
BenchmarkWithEmptyInterfaceString-8 50000000 30.7 ns/op

Well used and with parsimony, in most of the case the empty interface should have a real impact on the performances of your application.

A Journey With Go

A Journey With Go Language Programming

Vincent Blanchon

Written by

French Gopher in Dubai

A Journey With Go

A Journey With Go Language Programming

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade