Nil isn't always nil in Go
I ran across some interesting behavior in Go today. Given this program, what would you expect to happen?
My first guess is that it would output this:
Trying &main.Owner{org:(*main.Organization)(nil), user:(*main.User)(nil)}
=> "NIL"
Trying &main.Owner{org:(*main.Organization)(0xc42000e200), user:(*main.User)(nil)}
=> "organization:group"
Trying &main.Owner{org:(*main.Organization)(nil), user:(*main.User)(0xc42000e250)}
=> "user:person"
However, that’s not what actually happens. Instead, you’d see this:
Trying &main.Owner{org:(*main.Organization)(nil), user:(*main.User)(nil)}
=> panic!! "invalid memory address or nil pointer dereference"
Trying &main.Owner{org:(*main.Organization)(0xc42000e200), user:(*main.User)(nil)}
=> "organization:group"
Trying &main.Owner{org:(*main.Organization)(nil), user:(*main.User)(0xc42000e250)}
=> panic!! "invalid memory address or nil pointer dereference"
To see why, it helps to see the output from the fmt.Printf
statements that are in Owner.DatabaseString
:
Trying &main.Owner{org:(*main.Organization)(nil), user:(*main.User)(nil)}
[0] <nil>
[1] (*main.Organization)(nil)
=> panic!! "invalid memory address or nil pointer dereference"
Trying &main.Owner{org:(*main.Organization)(0xc42000e200), user:(*main.User)(nil)}
[0] <nil>
[1] &main.Organization{name:"group"}
=> "organization:group"
Trying &main.Owner{org:(*main.Organization)(nil), user:(*main.User)(0xc42000e250)}
[0] <nil>
[1] (*main.Organization)(nil)
=> panic!! "invalid memory address or nil pointer dereference"
I think this is happening because Go interface types are really a type plus a value. The call to GetOrganization()
returns a nil Organization
, but not a nil DatabaseStringer
.