DEV Community

Cover image for In Go nil is not equal to nil, sometimes
Pavel Kutáč
Pavel Kutáč

Posted on

In Go nil is not equal to nil, sometimes

In some cases, Go returns false when comparing nil variable and nil. This might be confusing for beginners. But this leads to some benefits too.


🇨🇿 V češtině si lze článek přečíst na kutac.cz

The following code is a nice example when variable val is nil but the comparison in the function returns false. A similar situation is with readFile function, which returns error. You can run code in Go Playground to prove to yourself it is true.

func nilPrint(val interface{}) string {
    if val == nil {
        return "I got nil"
    }
    return fmt.Sprintf("I got %T type with value '%v'", val, val)
}

func readFile() error {
    var err *fs.PathError
    fmt.Println(err == nil)
    return err
}

func main() {
    // Prints: I got string type with value 'Some value'
    fmt.Println(nilPrint("Some value"))
    // Prints: I got nil
    fmt.Println(nilPrint(nil))
    // Prints: true
    // but then: I got *string type with value '<nil>'
    var val *string
    fmt.Println(val == nil) // Prints true
    fmt.Println(nilPrint(val))

    fmt.Println("\nWith error interface")
    // Prints: true (inside readFile)
    // but then: false (in main method)
    err := readFile()
    fmt.Println(err == nil)
}
Enter fullscreen mode Exit fullscreen mode

The reason of this is interface

This behavior is caused by using interface{} as an input type. Which is something like Any. The second function returns error, which is also interface. The
comparison then returns false, because the value is null, but it has also data type. That is the reason why it is not equal to "raw" nil. If you are comparing variable with a known type, you are not affected by this behavior.

Solution with reflection

The way to fix the function which is returning error is simple. Do not set concrete error type, but stay with error type. So changing first line to this var err error. That is also best practise.

In the second case it might be little bit trickier. Changing data type is not so easy, because we want to accept anything. So the reflection package must be used here.

if val == nil || (reflect.ValueOf(val).Kind() == reflect.Ptr && reflect.ValueOf(val).IsNil()) {
    return "I got nil"
}
Enter fullscreen mode Exit fullscreen mode

Calling methods on nil object

I'm not sure this is related to behavior described above. But in my eyes it is similar.

Go doesn't have methods like other OOP languages. In Go, we call it receivers, which acts similarly. But there is a main difference. If the variable of type is nil, you can still call its receivers, or methods if you want. The code below does not panic but works correctly. Check it on Go Playground.

type JSONParser struct {
    raw string
}

func (p *JSONParser) Length() int {
    if p == nil {
        return 0
    }
    return len(p.raw)
}

func main() {
    var parser *JSONParser
    fmt.Println(parser.Length()) // Prints: 0

    parser = &JSONParser{raw: `{"just": "show", "some_result": 255}`}
    fmt.Println(parser.Length()) // Prints: 36
}
Enter fullscreen mode Exit fullscreen mode

Discussion (0)