type s struct {
}
func (e *s) Error() string {
return "a string"
}
x := (*s)(nil)
y := error(x)
I'm trying to understand why a nil pointer when converted to an interface produces a non-nil value.
Is this a bug?
So, the thing is that a nil pointer can still fulfill an interface. It's a valid value that has the correct methods.
type myStruct struct {}var NilMyStruct = &myStruct{} // a special pointerfunc (self *myStruct) Foo() {if self == NilMyStruct { ... } else { ... }}
I would like it if "var a interface{} = []byte(nil)" also set the type to be the nil in a. (See example 1)
======== example 1 ========var a interface{} = []byte(nil)a == nil // i wish this were true.
If you need an "early" panic, be explicit:
func (g *Grumpy) SayHi() string {
if g == nil {
panic(42)
}
// ...
}
However, it's not the usual approach to check the receiver like this.
If it's never used, it doesn't matter if it's nil. If it gets used,
you'll get the desired nil pointer dereference runtime error (perhaps
later).
(continued...)func MakeGreeter() Greeter {var g *Grumpy...if g == nil { return nil }return g}=================
> That would be deeply wrong. The value stored in a isn't> nil, /because/ it carries the type information ([]byte) as
> well as the value information (nil).
I'm suggesting that the type information be set to nil should the value be a nil pointer, thus making all nil values indistinguishable.
> Since a could hold (say) a *string or a *int, and these should
> be distinguishable even when the pointer value is nil,> then at most one of those cases could be forced to be> interface{}(nil). Better that neither is.
You haven't explained *why* it's good or necessary to distinguish between different nil types in an interface variable.Why must "at most one of those cases be forced to be interface{}(nil)"?
Go aims to have concepts be orthogonal. You are suggesting thatstoring a pointer value in a variable of interface type should act
differently than storing a non-pointer value. You are suggesting that
pointers have a privileged zero value that is not present for some
other types.
Presumably maps and channels would act like pointers
with regard to nil values, but what about slices?
What about structs that contain only pointer fields?
Also, now storing a value in an interface and then doing a type switch will act differently
depending on the type and the value.
My purpose in asking these questions is not to find out the answer, but to point out that your
proposal makes the language more complex.
Ian
So far I don't see how it would make the language any more complex.
Think about how this would be described in the language specification.You'd have to add, not take away. That, by definition, is more complexity.
x
is of pointer type and has the value nil
and x.f
denotes a struct field, assigning to or evaluating x.f
causes a run-time panic.x
is of interface type and has the value nil
, calling or evaluating the method x.f
causes a run-time panic.What surprises me is that this is such a problem for you.It's not something that I see in my own code, and not in the other code that I read.
Think about how this would be described in the language specification.You'd have to add, not take away. That, by definition, is more complexity.Actually it's the other way around. For example, see this under "Selectors":
- If
x
is of pointer type and has the valuenil
andx.f
denotes a struct field, assigning to or evaluatingx.f
causes a run-time panic.- If
x
is of interface type and has the valuenil
, calling or evaluating the methodx.f
causes a run-time panic.With my proposed changes, the distinction goes away.
Furthermore, in the FAQ, the question "Why is my nil error value not equal to nil?" goes away.Even the FAQ admits that the "situation can be confusing"
What surprises me is that this is such a problem for you.It's not something that I see in my own code, and not in the other code that I read.I've been coding in Go for over a year and I've just encountered it. It's not "such" a problem for me, I'm merely suggesting an improvement to the language.
You'll bump into it too eventually while refactoring your code, changing method signatures to return an interface type instead of a struct pointer.
Anyways, maybe a more palatable suggestion is to have a new operator that does what I want.
[...]
What would have been the downside of treating an interface with a nil
value like a nil
pointer?
> What makes nil pointers special that they should be comparable without type information?As it is, nothing.As a hack you could fit in an extra bit of information in the interface variable, in the least significant bit of the type pointer, set to 1 if the type is a pointer and 0 otherwise.Then, if the type pointer's least significant bit is set AND the value is zero, then you know you have a nil pointer.
I'm trying to understand why a nil pointer when converted to an interface produces a non-nil value.In the following example (available in full here):type s struct {
}func (e *s) Error() string {
return "a string"
}x := (*s)(nil)
y := error(x)x is nil but y is non-nil, even though the underlying type (according to reflect.TypeOf) of both variables is *s.The example is artificial, but the same conversion behaviour occurred when returning a nil pointer from a function with return type error. I was very surprised the caller of the function behaved as if there had been an error.Is this a bug?