The nil-interface wart actually does result in comparison issues, and it's something that trips people up all the time:
package main
import (
"fmt"
"io"
)
type Thing struct{}
func (t *Thing) Close() error { return nil }
func main() {
var x *Thing
var y io.Closer = x
fmt.Printf("x == nil -> %#v\n", x == nil) // true
fmt.Printf("y == nil -> %#v\n", y == nil) // false
}
Here, both x and y are conceptually nil, but y cannot be compared to nil.
Go is a strict language, but it's curiously lax about many things, including this. "go vet" won't even warn you that you're unintentionally wrapping nil in an interface. This goes way beyond just a trivial example like the above one, though: Any general-purpose code that has to deal with arbitrary interface{} values can't just check for nils, but need to do things like this:
func UnwrapReflectValue(v reflect.Value) interface{} {
if !v.IsValid() {
return nil
}
if v.IsNil() {
return nil
}
if v.Kind() == reflect.Ptr {
v = v.Elem()
if v.IsNil() {
return nil
}
}
if v.Kind() == reflect.Interface {
v = v.Elem()
}
return v.Interface()
}
I don't know why Go doesn't let "y == nil" return true here; boxed values are supposed to have the same high-level semantics as unboxed ones, and off the top of my head I can't think of any code where changing the current behaviour would cause breakage.