4

I ran into a strange bug today. I had a function:

func Foo(s *someStruct) {
    fmt.Printf("s is %v\n", s)
    if s!=nil {
        fmt.Printf("s is not nil")
        ...
    }
}

I would call the function like:

var s *someStruct
Foo(s)

And then I decided to convert the structure into interface:

func Foo(s someStructInterface) {
    fmt.Printf("s is %v\n", s)
    if s!=nil {
        fmt.Printf("s is not nil")
        ...
    }
}

Which gave me a strange output:

s is null
s is not nil

While I expected to get s is nil, which is what I was getting usually. What is the difference between null and nil in this scenario in Go and how can I check if something is null or nil to execute the code properly?

ThePiachu
  • 8,695
  • 17
  • 65
  • 94
  • 1
    Possible duplicate of [Hiding nil values, understanding why golang fails here](http://stackoverflow.com/questions/29138591/hiding-nil-values-understanding-why-golang-fails-here#29138676). – icza Feb 16 '16 at 22:07
  • 3
    The output from your interface example is `s is ` and `s is not nil`. – peterSO Feb 16 '16 at 22:17

1 Answers1

4

An interface value contains a reference to a type and a value. In the following code:

var s *someStruct
Foo(s)

the interface value passed to Foo contains a reference to the type *someStruct and a nil.

The statement fmt.Printf("s is %v\n", s) outputs s is <nil> because of the following: The %v format prints a value using the default format for the type. The value s contains a pointer type. The default format for a pointer type is %p. The %p format prints nil pointers as <nil>.

The expression s != nil evaluates to true because an interface value is equal to nil if and only if the type reference is nil. In this case, the interface value references the type *someStruct.

Charlie Tumahai
  • 113,709
  • 12
  • 249
  • 242
  • 6
    I don't understand where the explicit word `null` came from. It's not a construct of Go at all. – Not_a_Golfer Feb 16 '16 at 22:04
  • I get this distinction and can extend that to explain the behavior of `Printf` however, I wouldn't consider this as answering the question so I recommend elaborating on that. – evanmcdonnal Feb 16 '16 at 22:04
  • @Not_a_Golfer I would guess there is a special case in `fmt` for `%v` with interface types however like I said, MuffinTop should explain that since he didn't really answer the question as much as point out some details about interfaces. – evanmcdonnal Feb 16 '16 at 22:05
  • 1
    @evanmcdonnal I tried to write a short playground for this, and didn't get `null` as an output. – Not_a_Golfer Feb 16 '16 at 22:06
  • @Not_a_Golfer interesting... Perhaps the answer is wrong. I was about to do the same until this answer was provided but maybe I should look into it a bit more :) – evanmcdonnal Feb 16 '16 at 22:07
  • 3
    @Not_a_Golfer: "null" shouldn't come from the fmt package. It's likely a custom type, with slightly incorrect terminology, something like http://play.golang.org/p/CRFKJxEkGE – JimB Feb 16 '16 at 22:20
  • 1
    @evanmcdonnal I elaborated the answer as you suggested. I am assuming that "null" in question is a typo and should read "" as pointed out in comment. If "null" is printed, then someStruct has a `String() string` method or some other customization used by the fmt package. – Charlie Tumahai Feb 16 '16 at 22:30
  • Yeah that makes sense. Couple interesting things at work there. Someone writing poorly in their custom types `String()` implementation makes a lot more sense than a special case for the `%v` format specifier. – evanmcdonnal Feb 16 '16 at 23:16