Tags Go

A very common question that comes up in Go forums is "how to I check that some type implements a certain interface?". A common immediate reaction is that the question makes no sense, because Go is statically typed, so the compiler already knows whether a type implements an interface or not. But it turns out that the question in the general sense is more nuanced, and it's worth spending some time understanding the variations folks are usually interested in.

Let's start with a basic example. Assume this Munger interface that has a single Munge method:

type Munger interface {
    Munge(int)
}

And say that we have a type that doesn't have a Munge method; for example, int. If we try to do this:

var i int
var mm Munger = i

The compiler will rightfully complain:

cannot use i (type int) as type Munger in assignment:
    int does not implement Munger (missing Munge method)

The same happens if you attempt to pass i into a function that expects a Munger, and so on.

So the gist of the common response is: you don't need to perform this check, the compiler will do it for you on first use.

A more deliberate compile-time check

It's sometimes useful to have a more conscious compile-time check that a certain type implements a certain interface. Think something similar to a static_assert in C++. A nice trick to accomplish this is:

var _ Munger = (*Foo)(nil)

This statement checks if Foo implements Munger at compile time [1]. It can be placed on the top-level (outside functions) in a .go file, and won't generate any executable code in case the check passes. There are plenty of examples of this pattern in the Go ecosystem; here's one from the standard library (io/multi.go):

var _ StringWriter = (*multiWriter)(nil)

After defining the multiWriter struct, the code checks if it implements the StringWriter interface. This can be useful to ensure that we get a clear compile error in an expected place if the interface changes in some way.

The trick here is the usage of nil to create a typed value for the compiler to see without declaring any explicit vars.

Run-time check

A more common request is checking whether a type implements an interface at run-time. Note that this is semantically different from what the compiler does for us - we actually want to make a run-time decision based on what interfaces a given type implements. This can be useful in many scenarios, such as testing, plugins etc.

At first it seems easy - Go has good support for type assertions, after all. But there's a problem. Suppose we have the Munger interface again, and some type Foo; we want to check whether Foo implements Munger. A type assertion would go like this:

var f Foo
_, ok := f.(Munger)

But the compiler complains:

invalid type assertion: f.(Munger) (non-interface type Foo on left)

This is because only values of interface types are allowed on the left-hand-side of a type assertion. So what can we do? Well, if the compiler wants an interface, we can give it an interface:

var f Foo
_, ok := interface{}(f).(Munger)

We start by converting f to the empty interface type. This conversion is always successful because all types implement the empty interface. Now the check will work and will return true if Foo implements Munger, and false otherwise.

Run-time check using reflection

Another way to accomplish the run-time check is using reflection:

var f Foo

iMunger := reflect.TypeOf((*Munger)(nil)).Elem()
// ... now iMunger is a reflect.Type representing Munger

ok := reflect.TypeOf(&f).Implements(iMunger)

The reflect machinery has access to the underlying implementation of Go objects and types at run-time, and it uses this information to answer queries such as "does this type implement that interface".

Note that this technique also uses the trick shown in the "deliberate compile-time check section", wherein a nil pointer is given a type in order to avoid a temporary object.


[1]More precisely, it checks if *Foo implements Munger. But due to the way Go automatically dereferences if needed, this must be true if Foo implements Munger.