| Having been at Google when Go was announced internally, I remember being disappointed that a modern statically typed language is repeating Tony Hoare's Billion Dollar Mistake (tm). (I was also disappointed that C interoperability required recompiling your C code using kenc so that it used the Go/Plan9 calling convention. Maybe this has since been fixed.) I would have expected at least something a maybe/option type (or another mechanism to make optionality and refrences orthogonal concepts), if not full algebraic data types. Allowing Nil everywhere forces lots of otherwise unnecessary Nil checks and introduces myriad opportunities for bugs. Stepping back and assuming that for whatever reason an ML/Haskel/Swift/Rust/etc.-like maybe/option type is out of the question: when a programmer is comparing a passed interface instance to nil, they're almost certainly trying to answer the question "can I really call the defined interface's methods on this instance?". Having done very little Go programming, my mental model is that interface pointers are pointers to a tuple of meta-information (including dynamic dispatch table) and a pointer to the concrete type. I can understand that both the meta-information and the pointer to the value are necessary when comparing interface pointers. However, I don't understand the utility in there being a distinction at a language or ABI level between an interface pointer to a null value and a null pointer to the interface <metadata, value> tuple. In what situations is the semantic distinction useful? There may be some domains where the semantic difference is important, but it seems to me that in those cases you're better off using a field of an enumerated type, for the sake of cleaning up the semantics of nil interfaces. Though, coming from languages with algebraic data types, (and C++, where they had the good sense to make null references undefined behavior), cleaning up semantics of Nil in a language with Hoare's Billion Dollar Mistake is a bit like passing a public safety ordinance requiring fire extinguishers to be on hand at all gasoline fights... definitely helpful on the one hand, but seeming to miss an understanding of the root problem on the other. |
The distinction for typed nil is useful because some receivers may work with a nil value. This whole thread enumerates the disadvantages pretty clearly, but I just wanted to point out that it _can_ be useful.
I do think compiler warnings would be helpful when this kind of thing happens implicitly, to prevent new language users from being confused for extended periods.