DEV Community

shivi28 for Kubernetes Community Days Chennai

Posted on

Go: nil == nil is true or false? Na tum jano na hum…

Go image
In this article, we will understand how to use == the operator in Go to compare object values. We will also look at scenarios where the behaviour of this operator looks like a bug in the language but it is due to a lack of understanding.

Let's go through the below example

var a *string = nil    
var b interface{} = a
fmt.Println("a == nil:", a == nil) // true 
fmt.Println("b == nil:", b == nil) // false 
fmt.Println("a == b:  ", a == b  ) // true
Enter fullscreen mode Exit fullscreen mode

To understand the above example lets start with a simple one:

var a int = 12
var b int = 12
c:= 12
fmt.Println("a == b :", a == b) // true
fmt.Println("a == c :", a == c) // true
Enter fullscreen mode Exit fullscreen mode

This is very obvious.
Let's twist the example

var a *string = nil
var b interface{} = nil
fmt.Println("a == nil:", a == nil) // true
fmt.Println("b == nil:", b == nil) // true
fmt.Println("a == b:",   a == b) // false (even though the value is
                                           nil for both a and b)
Enter fullscreen mode Exit fullscreen mode

To understand the last case, let us dive deeper into it.

In Go, every pointer variable has two values associated with it <type, value> The fact that every variable needs a type is the reason why we can not have a nil value assigned to a variable whose type is not defined. That's why we can not write x := nil because we don't mention the type of x and we get the following error use of untyped nil

Now let's see our problem again

var a *string = nil      // a is <*string, nil>
var b interface{} = nil  // b is <nil, nil>
fmt.Println("a == nil:", a == nil) // true
fmt.Println("b == nil:", b == nil) // true
fmt.Println("a == b:", a == b)    // false <*string,nil>!=<nil, nil>
Enter fullscreen mode Exit fullscreen mode

In our case variable a actually represent <*string, nil> and interface{} default type is nil so variable b is <nil, nil>.
So that's why when we say a == b then we are actually comparing <*string,nil> == <nil, nil> which is false.

Now come back to our main example

var a *string = nil     // a is <*string, nil>
var b interface{} = a 
fmt.Println("a ==nil:",a==nil)//true(<*string, nil>==<*string, nil>)
fmt.Println("b == nil:", b == nil) //false (<*string,nil>==<nil,nil>    fmt.Println("a == b:  ", a == b  ) // true
Enter fullscreen mode Exit fullscreen mode

When we do a == nil , == the operator compares type as well as value. Here the value is nil for both LHS and RHS, but what will be the type of nil ???

When nil(hard-coded value) is compared with an object, the type of nil is the same as the declaration type of object with whom it is compared.

So in the case of a == nil we are doing <*string, nil> == <*string, nil>

In the case of b == nil , RHS is <nil, nil> because the declaration type of b is interface{} which is nil (default). Hence when we did

var b interface{} = a
Enter fullscreen mode Exit fullscreen mode

Then we assigned the value of a to variable b which means b now refers to <*string, nil> . Hence LHS != RHS

Note: var b interface{} = a does not change the declaration type of b variable.

Conclusion

This issue occurs frequently in industrial code like below code snippet is very common in Go where we can face such error.

var resp string
var err error
resp, err = CallFunction()
if err != nil{
   // code inside this if statement will be executed if return type  of CallFunction doesn't match with error
}
func CallFunction() custom.Error{
 // return pointer variable
}
Enter fullscreen mode Exit fullscreen mode

Here is the playground for more experimentation https://play.golang.org/p/BnPPXEs9_Oq

So it's always better to check that the return type of called function and type of receiving variables in the caller function should match.

Top comments (0)