2

I'm trying to compare the identity of 2 maps

package main

import "fmt"

func main() {
    a := map[int]map[int]int{1:{2:2}}

    b := a[1]
    c := a[1]

    // I can't do this: 
    // if b == c
    // because I get: 
    // invalid operation: b == c (map can only be compared to nil)

    // but as far as I can tell, mutation works, meaning that the 2 maps might actually be identical
    b[3] = 3

    fmt.Println(c[3]) // so mutation works...


    fmt.Printf("b as pointer::%p\n", b)
    fmt.Printf("c as pointer::%p\n", c) 

    // ok, so maybe these are the pointers to the variables b and c... but still, those variables contain the references to the same map, so it's understandable that these are different, but then I can't compare b==c like this
    fmt.Printf("&b::%p\n", &b)
    fmt.Printf("&c::%p\n", &c)  

    fmt.Println(&b == &c)
}

this produces the following output:

3
b as pointer::0x442280
c as pointer::0x442280
&b::0x40e130
&c::0x40e138
false

What's especially confusing to me is that while b as pointer::0x442280 and c as pointer::0x442280 seem to have the same values, which indeed would confirm to me my suspicion that those variables somehow point to the same dict.

So does anyone know how I can make go tell be that b and c are "the same object"?

vlad-ardelean
  • 7,480
  • 15
  • 80
  • 124
  • 1
    Have you already tried with [DeepEqual](https://golang.org/pkg/reflect/#DeepEqual)? – Matteo Oct 25 '18 at 13:41
  • 2
    I have not tried before you explicitly asked me, because given its name, the `reflect.DeepEqual` function seemed to do the exact opposite of what I wanted. However, this function does multiple things, one of which being what I want. It does work in my case, as it returns `true` if the pointers are equal. However, if I wanted to distinguish identity and equality, I would need another solution. So this solves my problem, but doesn't satisfy me in a more general sense :P Thanks a lot though! – vlad-ardelean Oct 25 '18 at 13:55
  • Can you tell me why do you need this? This may be good for an exercise, but I don't think this is ever needed in Go. – icza Oct 25 '18 at 15:17
  • This is an exercise, I admit. I was designing an algorithm that, if knowing it had 2 references to the same map, it could just update one of them. If however the 2 maps were not the same, but they just had the same values, I needed to discard one of them... I won't go into the exact details, but imagine it to be basically deduplication algorithm. – vlad-ardelean Oct 25 '18 at 15:22
  • Possible duplicate of [Why does go forbid taking the address of (&) map member, yet allows (&) slice element?](https://stackoverflow.com/questions/32495402/why-does-go-forbid-taking-the-address-of-map-member-yet-allows-slice-el) – Neil Fenwick Oct 25 '18 at 18:58
  • @icza How about a function that takes two maps and modifies one based on values in the other. It might be required to return an error if someone accidentally passes in the same map twice (https://play.golang.org/p/nCVPkMFFc6t) . Or perhaps you are writing a unit test and you want to check that two result maps do (or do not) have the same identity. Or perhaps you have a special sentinel map and you want to compare identity of a map against the sentinel map. – Chris Drew Oct 25 '18 at 19:23

2 Answers2

2

Not pretty but you can use reflect.ValueOf(b).Pointer():

package main

import (
    "fmt"
    "reflect"
)

func main() {
    a := map[int]map[int]int{1: {2: 2}}

    b := a[1]
    c := a[1]

    d := map[int]int{2: 2}

    fmt.Println(reflect.ValueOf(b).Pointer() == reflect.ValueOf(c).Pointer())
    fmt.Println(reflect.ValueOf(c).Pointer() == reflect.ValueOf(d).Pointer())
}
Chris Drew
  • 14,926
  • 3
  • 34
  • 54
0

Ok, so I'm obviously new to the language, and I won't start criticizing it so soon, but this is the solution I found:

Python code:

obj1 is obj2

Javascript code:

obj1 === obj2  // for objects, which is what I care about

Java code:

obj1 == obj2

And then there's go code:

fmt.Sprintf("%p", obj1) == fmt.Sprintf("%p", obj2)

Yes, it's exactly what it looks like: I get the string representation of pointers to the 2 variables, and compare those. And the strings look like this 0x442280.

fmt.DeepEqual is not the solution for me, because

  1. it checks whether the pointers are equal and then
  2. it then checks whether the values in the map are equal

This is completely not what I want. I want to know only if the maps are exactly the same object, not wether they contain the same values

vlad-ardelean
  • 7,480
  • 15
  • 80
  • 124