Why might you return nil
In many languages, if you want to represent “nothing” is returned, a common pattern is to use nil as a return value. A common alternative to this is the NullObjectPattern, since a 0/nil/null value generally does not respond to the same number of messages as a legitimate object value. This far more sparse interface is why languages like Ruby have introduced a Safe Navigation Operator. In languages that expose memory directly or indirectly like C++, trying to call object methods on a pointer to NULL could cause mangling of memory offset from that “zero” address.
What happens in Golang with a nil return

If you have a reference or pointer return type, you can specify nil
as a return value from it:
type foo struct {
}
func fooMeOncePointerWithNil() *foo {
return nil
}
So if you’re writing a test for this (trivial) function, you might be tempted to write
func TestFooMeOncePointerToArrayWithNil(t *testing.T) {
assert.Equal(t, nil, fooMeOncePointerToArrayWithNil(), "Test did not return nil")
}
But your assertion will fail, because the return value is *not* nil
:
❯ go test
--- FAIL: TestFooMeOncePointerToArrayWithNil (0.00s)
main_test.go:23:
Error Trace: /Users/tpowell/projects/golang/nilTest/main_test.go:23
Error: Not equal:
expected: <nil>(<nil>)
actual : *[]testy.foo((*[]testy.foo)(nil))
Test: TestFooMeOncePointerToArrayWithNil
Messages: Test did not return nil
FAIL
exit status 1
FAIL testy 0.104s
The actual type is nil
cast to a *[]testy.foo
cast to a *[]testy.foo
.
You can see this with returning to a pointer to an array of strings more clearly:
func stringPointerToArrayNil() *[]string {
return nil
}
func TestStringNil(t *testing.T) {
assert.Equal(t, nil, stringPointerToArrayNil(), "Function did not return nil")
}
Which fails similarly, although slightly more readably:
--- FAIL: TestStringNil (0.00s)
main_test.go:42:
Error Trace: /Users/tpowell/projects/golang/nilTest/main_test.go:42
Error: Not equal:
expected: <nil>(<nil>)
actual : *[]string((*[]string)(nil))
Test: TestStringNil
Messages: Function did not return nil
FAIL
exit status 1
FAIL testy 0.246s
What Technically Works?
So how we make a nil
return value match? Well, you can typecast nil
explicitly to match the implicit casting of the returned nil
:
func TestPassFooMeOncePointerToArrayWithNil(t *testing.T) {
assert.Equal(t, (*[]foo)(nil), fooMeOncePointerToArrayWithNil(), "Test did not return nil")
}
Now you’ll get:
❯ go test
PASS
ok testy 0.141s
A better “nil”?
Having to contort a language to do a basic thing is usually an indicator you’re probably using it wrong. In this case, perhaps you just want an empty array:
func fooMeOnceArray() []foo {
return []foo{}
}
Now you can validate this with the len
function on the returned array:
func TestFooMeOnceArray(t *testing.T) {
assert.Equal(t, 0, len(fooMeOnceArray()), "Test did not return nil")
}
This, of course, passes, but tested against the number of items returned instead of checking for an arbitrary nil
value.
Maybe you just want to check error
Golang supports multiple return values, and you can add a return of an error
type:
func fooMeOnceArrayError() ([]foo, error) {
return []foo{}, nil
}
The error
type *can* be cleanly compared to nil
:
func TestFooMeOnceArrayError(t *testing.T) {
_, error := fooMeOnceArrayError()
assert.Equal(t, nil, error, "Test did not return nil")
}
This comparison to nil
passes:
❯ go test
PASS
ok testy 0.238s
Conclusion
The bigger lesson in all of this is that if the direction that you’re going down in a language feels unnatural, there might be a better way to do things. Or you might not even be using a pattern that is preferred for the language. Take a step back and look at the bigger picture.