DEV Community

Victor Basumatary
Victor Basumatary

Posted on

nil Inteface Values Gotcha

#go

Consider the following program. What do you think will be printed? true or false?

package main

type MyInterface interface {
    DoSomething()
}

type MyInterfaceImplementation struct{}

func (impl *MyInterfaceImplementation) DoSomething() {}

func getMyInterfaceImplementation() *MyInterfaceImplementation {
    return nil
}

func getMyInterface() MyInterface {
    return getMyInterfaceImplementation()
}

func main() {
    fmt.Println(getMyInterface() == nil)
}
Enter fullscreen mode Exit fullscreen mode

If you said true you will be surprised to find out that it's actually false.

Let's print out what's returned by getMyInterface()

func main() {
    fmt.Printf("%v %t\n", getMyInterface(), getMyInterface() == nil)
}
Enter fullscreen mode Exit fullscreen mode
$ <nil> false
Enter fullscreen mode Exit fullscreen mode

That doesn't make any sense! We are getting a nil but the equality check with nil returns false. Why? Let's dig in a little deeper.

func main() {
    fmt.Printf("%#v %t\n", getMyInterface(), getMyInterface() == nil)
}
Enter fullscreen mode Exit fullscreen mode
$ (*main.MyInterfaceImplementation)(nil) false
Enter fullscreen mode Exit fullscreen mode

If you have a variable whose type is an interface that variable is actually storing an interface value, NOT the value that you set it to. The same applies when your function returns a value of an interface type.

In the Go runtime interface values are implemented as tuples, meaning it is made up of two things. The first is the concrete type of the interface (here it is *main.MyInterfaceImplementation) and the second is the concrete value (nil). This is how the Go runtime tracks which interface implementation is being referenced and where the value is in memory, or if it nil.

So getMyInterface() is not returning a nil but rather an interface value whose concrete value is nil. If we want our function to return a nil instead we need to make the following change.

func getMyInterface() MyInterface {
    impl := getMyInterfaceImplementation()

    if impl == nil {
        return nil
    }

    return impl
}
Enter fullscreen mode Exit fullscreen mode
$ <nil> true
Enter fullscreen mode Exit fullscreen mode

Top comments (0)