Logic behind failing Nil check?


(Kevin) #1

hi all,
Im relatively new to go (but been a developer for over 15yrs) and wrote some code like this and it perplexed me for a couple hours.

var _ error = &Error{}
type Error struct{ message string }
func (e *Error) Error() string { return e.message }
func call1() error  { return call2() }
func call2() *Error { return nil }
func Test_Gotcha(t *testing.T) {
	defer func() {
		if r := recover(); r != nil {
			t.Errorf("Failed with a panic for null usage")
		}
	}()
	err := call1()
	if err != nil {
		anError, ok := err.(*Error)
		if ok {
			fmt.Printf("this panics on nil reference %s\n", anError.message)
		}
	}
}

Im wondering what the logic is behind the err!=nil not catching the <*Error> nil returned from call2?
Go seems straight pretty easy and straight forward most of the time but this seems to be a gotcha in a really bad place?
PS Im using go 13.1


(Jake Montgomery) #2

This is addressed in the Go “FAQ” on the main go site. See https://golang.org/doc/faq#nil_error


(Huseyin Ozdemir) #3

Hello,

Can you expand to testing struct or can you share us a runing example on play golang?


(Kevin) #4

Yeah thanks :).
It still does not explain the logic behind it … why does it do this? and why is it designed like this ?


(Kevin) #5

hi yep … the code in the description replicated it when the anError.message panics on the value of the type being nil


(Jakob Borg) #6

One bit of the logic behind it is that nil pointers in Go aren’t always as “bad” as in other languages. For example it’s ok to call methods on nil pointers, and those methods can do useful things. This means that having an interface with T=*foo V=nil might be a useful and intended thing. Hence the nil interface is strictly the one that has no type (nor value).

In another sense it would be odd for an interface to be nil yet contain information (the type). As it is, nil strictly means the zero value which is simple and easy to understand - although it causes this annoying caveat with errors.