69

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 := 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

3
  • 6
    this is in the FAQ, using the error interface as an example: golang.org/doc/faq#nil_error
    – Mr_Pink
    Commented Mar 19, 2015 at 14:13
  • 1
    this example made my brain hurt. shower is an interface that contains getWater() that returns a slice of shower? Further on, display implements shower, and also has a child field called SubDisplay that is of type display? Why such strange names and relations between display, shower and water?
    – a3y3
    Commented Dec 4, 2024 at 21:48
  • @a3y3 lol same sentiments here
    – Kelv1nG
    Commented Feb 23 at 5:59

3 Answers 3

103

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:

  • you want to have a value as an interface type (shower)
  • but the value you want to store in the slice is not of type shower but a concrete type

So 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.

8
  • 1
    that's a pretty... big fail isn't it? How can I write a library that provides interfaces that way? I could assure that it works correctly if the users provides correct types with nil value. I guess if x == (shower)(nil) would make sense but that is just shocking..
    – sharpner
    Commented Mar 19, 2015 at 6:52
  • 5
    There is nothing shocking about it. Your return a slice of two interface values, both are non-nil. One of those non-nil interface values contains a nil value. The interface value has to be non-nil to contain anything, even a nil. You can either fix it like icza suggested, or redesign your API, e.g. not returning a slice of interfaces.
    – Volker
    Commented Mar 19, 2015 at 7:06
  • 2
    @sharpner You can provide a library which uses/returns values of interface types. But if the value is "missing", return nil explicitly.
    – icza
    Commented Mar 19, 2015 at 7:11
  • I'm still trying to wrap my head around how to redesign the api. Maybe a typedef something []shower will get me further or I don't know yet. But I really learned something quite new about go today. My example simplifies the real problem somewhat. In the final implementation, the user of my library has to implement getWater() and therefore can make mistakes. So, since I got to assume that this will happen, I needed to assure that no nil values are in the slice. I anticipated that users can return pointer to structs or structs that implemented the interface....
    – sharpner
    Commented Mar 19, 2015 at 7:42
  • 10
    A nil pointer is not an invalid value. Note that you can call methods on nil pointers just fine: play.golang.org/p/Agd8eIwaKZ Try reading my post about nil pointer and nil interfaces, it may help: npf.io/2014/05/intro-to-go-interfaces/#toc_4
    – Nate Finch
    Commented Mar 19, 2015 at 17:59
17

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.

0

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.

1
  • 2
    While this satisfies the original question, it defeats the purpose of an interface, since it only works if a display type is used.
    – Frug
    Commented Oct 29, 2020 at 17:44

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.