I fail to understand how to correctly assure that something is not nil
in this case:
package main
type shower interface {
getWater() []shower
}
type display struct {
SubDisplay *display
}
func (d display) getWater() []shower {
return []shower{display{}, d.SubDisplay}
}
func main() {
// SubDisplay will be initialized with null
s := display{}
// water := []shower{nil}
water := s.getWater()
for _, x := range water {
if x == nil {
panic("everything ok, nil found")
}
// First iteration display{} is not nil and will
// therefore work, on the second iteration
// x is nil, and getWater panics.
x.getWater()
}
}
The only way I found to check if that value is actually nil
is by using reflection.
Is this really wanted behaviour? Or do I fail to see some major mistake in my code?
Play link here
nil s in Go. nil is a frequently used and important predeclared identifier in Go. It is the literal representation of zero values of many kinds of types. Many new Go programmers with experiences of some other popular languages may view nil as the counterpart of null (or NULL ) in other languages.
if err != nil { return err } > is outweighed by the value of deliberately handling each failure condition at the point at which they occur. Key to this is the cultural value of handling each and every error explicitly.
false isn't nil, and by reflexivity of identity, nil isn't false. Unfortunately, opinion is the only argument here. As you have guessed from that thread, neither option is any better than the other.
In the Go programming language, nil is a zero value. Recall from unit 2 that an integer declared without a value will default to 0. An empty string is the zero value for strings, and so on. A pointer with nowhere to point has the value nil .
The problem here is that shower
is an interface
type. Interface types in Go hold the actual value and its dynamic type. More details about this: The Laws of Reflection #The representation of an interface.
The slice you return contains 2 non-nil
values. The 2nd value is an interface value, a (value;type) pair holding a nil
pointer value and a *display
concrete type. Quoting from the Go Language Specification: Comparison operators:
Interface values are comparable. Two interface values are equal if they have identical dynamic types and equal dynamic values or if both have value
nil
.
So if you compare it to nil
, it will be false
. If you compare it to an interface value representing the pair (nil;*display)
, it will be true
:
if x == (*display)(nil) {
panic("everything ok, nil found")
}
This seems unfeasible as you'd have to know the actual type the interface holds. But note that you can use reflection to tell if a non-nil
interface value wraps a nil
value using Value.IsNil()
. You can see an example of this on the Go Playground.
Why is it implemented this way?
Interfaces unlike other concrete types (non-interfaces) can hold values of different concrete types (different static types). The runtime needs to know the dynamic or runtime-type of the value stored in a variable of interface type.
An interface
is just a method set, any type implements it if the same methods are part of the method set of the type. There are types which cannot be nil
, for example a struct
or a custom type with int
as its underlying type. In these cases you would not need to be able to store a nil
value of that specific type.
But any type also includes concrete types where nil
is a valid value (e.g. slices, maps, channels, all pointer types), so in order to store the value at runtime that satisfies the interface it is reasonable to support storing nil
inside the interface. But besides the nil
inside the interface we must store its dynamic type as the nil
value does not carry such information. The alternate option would be to use nil
as the interface value itself when the value to be stored in it is nil
, but this solution is insufficient as it would lose the dynamic type information.
Some people say that Go's interfaces are dynamically typed, but that is misleading. They are statically typed: a variable of interface type always has the same static type, and even though at run time the value stored in the interface variable may change type, that value will always satisfy the interface.
In general if you want to indicate nil
for a value of interface
type, use explicit nil
value and then you can test for nil
equality. The most common example is the built-in error
type which is an interface with one method. Whenever there is no error, you explicitly set or return the value nil
and not the value of some concrete (non-interface) type error variable (which would be really bad practice, see demonstration below).
In your example the confusion arises from the facts that:
shower
)shower
but a concrete typeSo when you put a *display
type into the shower
slice, an interface value will be created, which is a pair of (value;type) where value is nil
and type is *display
. The value inside the pair will be nil
, not the interface value itself. If you would put a nil
value into the slice, then the interface value itself would be nil
and a condition x == nil
would be true
.
Demonstration
See this example: Playground
type MyErr string
func (m MyErr) Error() string {
return "big fail"
}
func doSomething(i int) error {
switch i {
default:
return nil // == nil
case 1:
var p *MyErr
return p // != nil
case 2:
return (*MyErr)(nil) // != nil
case 3:
var p *MyErr
return error(p) // != nil because the interface points to a
// nil item but is not nil itself.
case 4:
var err error // == nil: zero value is nil for the interface
return err // This will be true because err is already interface type
}
}
func main() {
for i := 0; i <= 4; i++ {
err := doSomething(i)
fmt.Println(i, err, err == nil)
}
}
Output:
0 <nil> true
1 <nil> false
2 <nil> false
3 <nil> false
4 <nil> true
In case 2 a nil
pointer is returned but first it is converted to an interface type (error
) so an interface value is created which holds a nil
value and the type *MyErr
, so the interface value is not nil
.
Let's think of an interface as a pointer.
Say you have a pointer a
and it's nil, pointing to nothing.
var a *int // nil
Then you have a pointer b
and it's pointing to a
.
var b **int
b = &a // not nil
See what happened? b
points to a pointer that points to nothing. So even if it's a nil pointer at the end of the chain, b
does point to something - it isn't nil.
If you'd peek at the process' memory, it might look like this:
address | name | value
1000000 | a | 0
2000000 | b | 1000000
See? a
is pointing to address 0 (which means it's nil
), and b
is pointing to the address of a
(1000000).
The same applies to interfaces (except that they look a bit different in memory).
Like a pointer, an interface pointing to a nil pointer would not be nil itself.
Here, see for yourself how this works with pointers and how it works with interfaces.
I'll take an alternative route to answer your concrete question, by providing the exact answer you were looking for:
Replace the check:
if x == nil {
panic("everything is ok. nil found")
}
with:
if _, ok := x.(display); !ok {
panic("everything is ok. nil found")
}
The idea here is that we are trying to convert the interface type (shower) to the concrete type display. Obviously the second slice item (d.SubDisplay) is not.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With