-1

I'm trying to understand how to check if two objects are the same when they implement the same interface.

Here is the example code:

package main

import (
    "fmt"
)

type shout interface {
    echo()
}

type a struct {}
func (*a) echo () {
    fmt.Println("a")
}

type b struct {}
func (*b) echo () {
    fmt.Println("b")
}

func compare(a, b shout) {
    //fmt.Println(&a, &b)
    if a == b {
        fmt.Println("same")
    } else {
        fmt.Println("not same")
    }
}

func main() {
    a1 := &a{}
    b1 := &b{}
    a2 := &a{}
    a1.echo()
    b1.echo()
    compare(a1, b1)
    compare(a1, a2)
    compare(a1, a1) 
}

https://play.golang.org/p/qo9XnbthMw

The result is:

not same
not same
same

a1 and a2 are not the same

But if uncomment the line#22

fmt.Println(&a, &b)

The result is:

0x1040a120 0x1040a128
not same
0x1040a140 0x1040a148
same
0x1040a158 0x1040a160
same

Does anyone can figure out what happened here? Does the Golang compiler optimize something?

Thanks

Jonathan
  • 19
  • 3

3 Answers3

2

This appears to be a more complicated example of https://github.com/golang/go/issues/8938.

The relevant parts of the Go spec are https://golang.org/ref/spec#Comparison_operators

Pointers to distinct zero-size variables may or may not be equal.

and https://golang.org/ref/spec#Size_and_alignment_guarantees

Two distinct zero-size variables may have the same address in memory.

Based on the title of the issue linked above (cmd/compile: optimisations change the behaviour of *struct{}), the difference is due to compiler optimizations.

Kale B
  • 136
  • 4
0

This is expected behavior. For background, == is an operator which compares the value of two objects. This is known as object equality. Comparing their pointer value, or their identity, is different. See the top answer on this similar post.

When you ask a1 == b1, you receive false because a1 is an instance of the a struct, whereas b1 is an instance of the b struct. Therefore, even though they implement the same interface, they are not == to each other. Consider your a struct and b struct where they had additional and different methods implemented in both (so a has an additional method foo() and b has an additional method bar()). Although a and b would implement the same interface, they would not be the same, nor would you expect or want them to be.

When you ask if a1 == a2, you receive true because a1 and a2 are just separate instances of the same struct. Referencing the post I linked above, a1 and a2 are equal, but do not share the same identity.

Finally, when you ask if a1 == a1, you are asking if the same instance of the same object is equal to itself, which of course is true. In this case, a1 shares both equality and identity with a1.

Community
  • 1
  • 1
  • 1
    Thanks for the explanation. Another question that I don't understand is why the fmt.Println() would change the result of the if statement? – Jonathan Dec 29 '16 at 08:04
0

You should use reflect.DeepEqual to compare struct, slice and map.

package main

import (
    "fmt"
)

type a struct{}

func main() {
    a1 := &a{}
    a2 := &a{}

    fmt.Printf("%p\n", a1)

    if a1 == a2 {
        fmt.Println("same")
    } else {
        fmt.Println("not same")
    }

}

The result is:

0x196a9c
not same

Using reflect.DeepEqual as below:

package main

import (
    "fmt"
    "reflect"
)

type a struct{}

func main() {
    a1 := &a{}
    a2 := &a{}

    fmt.Printf("%p\n", a1)

    if a1 == a2 {
        fmt.Println("same")
    } else {
        fmt.Println("not same")
    }

    fmt.Println(reflect.DeepEqual(a1, a2))
}

The Result is:

0x196a9c
same
true

Just golang compiler optimization i guess.

timestee
  • 1,086
  • 12
  • 36