Golang: An interface holding a nil value is not nil

Let’s start directly with an example (go playground):

package main

import "fmt"

func main() {

    var a interface{}
    fmt.Printf("a == nil is %t\n", a == nil)  

    var b interface{}
    var p *int = nil
    b = p
    fmt.Printf("b == nil is %t\n", b == nil)
}

What is your expectation for the output? It will end up like:

a == nil is true
b == nil is false

It is somehow counter-intuitive at the first glance, but it makes a lot more sense if we explore a little bit about the reflection model in Golang.

Under the hood, an interface in Golang consists of two elements: type and value. When we assign a nil integer pointer to an interface in our example above, the interface becomes (*int)(nil), and it is not nil. An interface equals nil only if both the type and value are nil.

Here is another example of this (go playground), which is a bad pattern to return the error:

package main

import "fmt"

func main() {
    err := subFunction()
    if err != nil {
        fmt.Println("ERROR")
    } else {
        fmt.Println("NO ERROR")
    }
}

func subFunction() error {
    var p *MyError = nil
    if false {   // will not come in this block, the value of p will be nil
        p = &MyError{"error"}
    }
    return p
}

type MyError struct{
    msg string
}

func (e MyError) Error() string {
    return e.msg
}

This code will always print “ERROR”. Actually, subFunction() will always return a non-nil error, because error is an interface that MyError implements and it is not nil when only the value is nil.

To fix this code, we need to update subFunction() to return nil error explicitly.

func subFunction() error {
    if false {
        return &MyError{"error"}
    }
    return nil
}

So, how can we check if the value of an interface is nil? We need to use the functions in reflect package. In our first example, we can validation if the value of b is nil with:

    fmt.Printf("b.value == nil is %t\n", b == nil || (reflect.ValueOf(b).Kind() == reflect.Ptr && reflect.ValueOf(b).IsNil()))

Conclusion

  • An interface holding nil value is not nil. An interface equals nil only if both type and value are nil.

References

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s