DEV Community

Cover image for When <nil> is not <nil>
Hercules Lemke Merscher
Hercules Lemke Merscher

Posted on • Updated on • Originally published at bitmaybewise.substack.com

When <nil> is not <nil>

You might have already heard that the null reference is the billion-dollar mistake in programming languages.

The famous and dreaded NullPointerException from Java might be your acquaintance or the segmentation fault in C, you name it, all commercial programming languages are drinking the Kool-Aid, there’s no denying it.

The billion-dollar mistake

The null reference was introduced in ALGOL, back in 1965 by Tony Hoare. In 2009, while speaking at a conference, he apologized for introducing null references in ALGOL, saying it was his “billion-dollar mistake” since it culminated in a series of unfortunate bugs and security issues in the last 40+ years.

Sir Hoare speaks at length about it in his talk at QCon from 2009: Null References: The Billion Dollar Mistake. If you have some time to spare, please go and check it out. Tony Hoare is one of such computer science legends still alive.

And there we Go

Sorry for the pun, but yeah, Go is a relatively new programming language, and still, it suffers from null references.

One good thing about Go is that everything is a value, you don’t have hidden exceptions flying around, you receive a value, you check it, simple as that.

Example:

err := db.Insert(ctx, record)
if err != nil {
    return fmt.Errorf("error while inserting record %+v: %w\n", record, err)
}
Enter fullscreen mode Exit fullscreen mode

If you’re either a seasoned Go developer or someone who just started in Go, you should be already familiar with this pattern to handle errors. It’s simple, there’s no magic behind it.

Not every time, though, a nil will be equal to nil in Go.

<nil> is not always <nil>

Why?

This problem in Go arises when we perform nil checks on interface values. An interface in Go holds a type and a value. A nil interface value is nil when its type and value are both unset. If we declare a variable as a pointer to an interface, it will hold the type but the value is still nil, and here is where lies the nil is not equal to nil.

Example:

func returnsError() error {
    var p *MyError = nil
    if bad() {
        p = ErrBad
    }
    return p // Will always return a non-nil error.
}
Enter fullscreen mode Exit fullscreen mode

The example above is from the official FAQ. There’s even a section just to explain this issue: Why is my nil error value not equal to nil?

Though the example above uses error values, this behavior will be present in any abstraction, and eventually, you might run into similar issue(s). Another good source speaking about this is David Cheney’s Practical Go advices, section “Understanding nil“.

If you really want to dive deeper, there are the go internals book and Russ Cox’s Go Data Structures: Interfaces.

A design issue?!

Some gophers may say it’s intended and we should educate ourselves, understanding the idiosyncrasies of using pointers to interfaces and be aware of possible implications. I’d rather not use nils at all, but it’s hard to avoid them when the language allows it.

People keep getting confused by that: err != nil when err == nil with custom error type

There’s even a proposal to address this in Go 2 with different nil kinds: proposal: Go 2: add kind-specific nil predeclared identifier constants

What’s your take?


If you liked this post, consider subscribing to my newsletter Bit Maybe Wise.

You can also follow me on Twitter.

Image from Unsplash.

Top comments (0)