But a bunch types you do expect to work can: Slices, maps and channels.
var m map[string]bool
m["foo"] = 1 // Nil, panic
var a []string
a[0] = "x" // Nil, panic
var c chan int
<-c // Blocks forever
This violates the principle of least surprise. Go has a nicely defined concept of "zero value" (for example, ints are 0 and strings are empty) until you get to these.
The most surprising nil wart, however, is this ugly monster:
package main
import "log"
type Foo interface {
Bar()
}
type Baz struct{}
func (b Baz) Bar() {}
func main() {
var a *Baz = nil
var b Foo = a
fmt.Print(b == nil) // Prints false!
}
This happens is because interfaces are indirections. They are implemented as a pointer to a struct containing a type and a pointer to the real value. The interface value can be nil, but so can the internal pointer. They are different things.
I think supporting nils today is unforgivable, but the last one is just mind-boggling. There's no excuse.
I don't think you're right that interfaces are implemented as a pointer to a struct. The struct is inline like any other struct, and it contains a pointer to a type and a pointer to the value, like `([*Baz], nil)` in your example. The problem is that a nil interface in Go is compiled to `(nil, nil)` which is different.
I don't think using nil to represent uninitialized data is a major issue-- if it were possible to catch uninitialized but queried variables at compile-time, that could be an improvement, but we want to give the programmer control to declare and initialize variables separately.
Interesting, because (reading up on this) value types can not be nil.
How often does typical Go code use values vs. interfaces or pointers? It seems like the situation is pretty similar to modern C++, which also does not allow null for value or reference types (only pointers) and encourages value-based programming. Nil is still a problem there, but less of one than in, say, Java, where everything is a reference.
In my own experience, nil basically only shows up when I've failed to initialize something (like forgetting to loop over and make each channel in an array of channels), or when returning a nil error to indicate a function succeeded. I've never run into other interfaces being nil, but I also haven't worked with reflection and have relatively little Go experience (~6 months).
The code that I've written regularly uses interfaces and pointers, but I'd guess 80% works directly with values.