For some context, I've been programming in Go for about six years now, and I've literally never even thought about this.<p>In general, you really haven't got much reason to be worried about something's "interface type", because if you're really worried about something's "type" (which can happen) you are almost certainly worried about it's "concrete type". The only interesting thing you can ask about the interface type directly would be "Does the value inside this interface implement this interface?", and the answer is statically yes, the compiler assured that, and the interface type is statically assured at runtime, so it's not a very interesting question. Even if fmt added a way to "see" the interface type passed in, I can't imagine what it would be useful for, because it could only ever be:<p><pre><code> var x SomeInterfaceType
// some number of lines of code
fmt.Printf("%I\n", x)
</code></pre>
which would statically print "SomeInterfaceType".<p>So, I mean, it's not like anything said in that blog post is <i>false</i> necessarily, but if you're collecting reasons to hate on Go's nil handling, there's no real justification in adding this to your list. I'd also add that I answer newbie questions a lot on Reddit, and nothing even remotely like this has ever come up there, either.
The predeclared identifier nil is a constant, like 0 or "".<p>Like 0 or "", nil is untyped. Go has both typed and untyped constants. 0 also is untyped, which is why you can write x==0 regardless of whether x is an int32 or an int64.<p>Unlike 0 or "", nil does not have a default type. The default type of a constant is the type that it is implicitly converted to when a type is required. For example, "x := 0" declares a new value x with the value 0, but 0 is untyped. Untyped integer constants have a default type of int, so x is given the type int.<p>Since nil does not have a default type, it's an error to write "x := nil".<p>You can declare a typed constant with the value 0 or nil. int32(0) is a constant with type int32 and the value 0. (* int32)(nil) is a constant with the type pointer-to-int32 and the value nil.<p>Variables of an interface type can hold any value that satisfies the interface. For example, a value of type io.Reader can hold any value that has a Read method with the appropriate signature.<p>The common confusion about nil occurs because you can compare an interface value to a non-interface value.<p><pre><code> var b *bytes.Buffer // b is a variable with type *bytes.Buffer
var r io.Reader // r is a variable with type io.Reader
r = b // r now holds a value with type *bytes.Buffer and value nil
b == nil // true: b is nil
r == b // true: r and b are equal
r == (io.Reader)(nil) // false: r is not a nil io.Reader
r == (*bytes.Buffer)(nil) // true: r contains a nil *bytes.Buffer
r == nil // false: r is not a nil io.Reader
</code></pre>
The confusing part is that last line. How can r not be nil, when it contains a nil value? And the reason is hopefully apparent from the previous two lines: It depends on the type of "nil".<p>Whether you find this a wart in the language or not, this is not a case of nil being either typed in theory or untyped in practice. The predeclared identifier "nil" is an untyped constant.
I'm afraid this rings slightly hollow for me.<p>We can likewise claim about C that "0 in C is typed in theory and sort of untyped in practice" because constant expressions of integer type that evaluate to 0 can serve as null pointers of any type:<p><pre><code> char *p = 0; // no cast required
if (p == 0) ... // no cast required
time_t t = time(0); // fine
char *q = 1; // error; requires (char *) 1.
</code></pre>
We can't think of this 0 as an object; it's just a source code token that provides a null pointer of the right type, which is statically obvious from the use.<p>The only time it's a problem is in unsafe interfaces:<p><pre><code> int old_style_string_fun();
int variadic_fun(char *first, ...);
old_style_string_fun(0);
variadic_fun("first", 0);
</code></pre>
Here, the wrong type is inferred; the 0 just behaves like the ordinary constant of type int. A null pointer to char was intended, which requires (char *) 0 must be used.<p>None of this challenges the fact that we can have a variable of type <i>int</i>, whose value is 0.
I'm not sure why it would be significantly better to have reliably "typed nil" over "untyped nil". The concept has no real definition to begin with: what matters about sound typing are the static guarantees a type brings, or by association even if this not really the same concept, the "dynamic guarantees" about the behavior of objets of some "dynamic type" (that is the variable used as a handle to the objet had no guarenteed static type, but in most cases the object themselves <i>have</i> a type). Acting on a "type" of nil values seems to make very little sense. Maybe there are obscur constructs where this would be handy, but at the first glance I would consider it probably indicative of a dirty hack, and recommend looking for alternate solutions.
Much discussion about nil in Go just yesterday:<p><a href="https://news.ycombinator.com/item?id=26635529" rel="nofollow">https://news.ycombinator.com/item?id=26635529</a>
It is very confusing that equality in JavaScript is not transitive: <a href="https://imgur.com/5pFXFbR" rel="nofollow">https://imgur.com/5pFXFbR</a>.<p>Apparently equality in Go is no longer transitive either...
'nil' in Go is just an identifier to represent the zero values of some kinds of type. A bare nil is always untyped and it is the only untyped value which has not a default type.<p>Zero values behave the same as non-zero values in many aspects.<p>More read: nils in Go <a href="https://go101.org/article/nil.html" rel="nofollow">https://go101.org/article/nil.html</a><p>The facts that several kinds of type share the same zero value literal representation really confuse many new gophers, but this is hardly a problem when you get familiar with the design.<p>There are proposals to remove the new-gopher confusion.<p>* <a href="https://github.com/golang/go/issues/22729" rel="nofollow">https://github.com/golang/go/issues/22729</a> use different zero identifiers for different kinds of type<p>* I remembered that there is a propsoal which propose using `null` for non-interface zero values but still using `nil` for interfaces. I couldn't find this issue now.