FAQ
It may be debatable what the correct behavior should be in this case, but
IMO the following *should* print true, but doesn't:

a1 := "arst"
a2 := "arst"
a3 := map[*string]bool{&a1: true}
a4 := map[*string]bool{&a2: true}
fmt.Println(reflect.DeepEqual(a3, a4))

For reference/sanity checking, these two both do match:

a5 := map[string]bool{a1: true}
a6 := map[string]bool{a2: true}
fmt.Println(reflect.DeepEqual(a5, a6))
a7 := map[int]*string{55: &a1}
a8 := map[int]*string{55: &a2}
fmt.Println(reflect.DeepEqual(a7, a8))

http://play.golang.org/p/jLTaCRTedt


Should DeepEqual be inspecting the types of map keys and dereferencing them
if they are pointers? It dereferences all other instances of pointers that
it encounters, so I would claim: yes.

Background: I'm building some large data structures out of text, and I'm
trying to avoid creating tens or hundreds of copies of each string, yet
still maintain many references to them to optimize the way I access them.
This approach works fine in code, but when writing tests, I ran into
trouble, because I am trying to test by building two versions of my data
structure and comparing them with a DeepEqual. This doesn't work because
they end up with different pointers as their keys, even though the values
of those pointers match.

Thanks,
Doug

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Search Discussions

  • Jan Mercl at Mar 11, 2013 at 7:19 am

    On Mon, Mar 11, 2013 at 8:03 AM, Doug Fawley wrote:
    It may be debatable what the correct behavior should be in this case, but
    IMO the following should print true, but doesn't:

    a1 := "arst"
    a2 := "arst"
    a3 := map[*string]bool{&a1: true}
    a4 := map[*string]bool{&a2: true}
    fmt.Println(reflect.DeepEqual(a3, a4))
    IMO the code behaves correctly: http://golang.org/ref/spec#Comparison_operators.

    http://play.golang.org/p/_cjafjgb10

    Should DeepEqual dereference pointers and compare the dereferenced
    values instead? Consider

    type node struct { next * node }

    n := &node{}
    n.next = n

    reflect.NewDeepEqual(n, n) // don't expect this to ever return

    Using a pointer to a string _does_ save memory, but only one machine
    word. String is a value type, roughly struct{p *byte, len int}. You
    can use in this case a string "dictionary":
    http://godoc.org/github.com/cznic/strutil#Dict. Comparing equal valued
    integers (string numercial identifiers) instead of string pointers
    should work in the above code.

    -j

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Dan Kortschak at Mar 11, 2013 at 7:32 am
    But it does, just not in this case where the value is a map key.

    http://play.golang.org/p/ScUVQ5Z_Eb
    On 11/03/2013, at 5:49 PM, "Jan Mercl" wrote:

    Should DeepEqual dereference pointers and compare the dereferenced
    values instead? Consider
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Jan Mercl at Mar 11, 2013 at 8:03 am

    On Mon, Mar 11, 2013 at 8:32 AM, Dan Kortschak wrote:
    But it does, just not in this case where the value is a map key.

    http://play.golang.org/p/ScUVQ5Z_Eb
    Ah, my bad. It shows that I, in the first approximation, don't touch
    reflection. I implanted how I would probably write DeepEqual. As it
    seemed to me dereferencing is not an option. Well, it's not "seemed",
    but "seems" still. I wonder, how DeepEqual manages cyclic data? Does
    it compare shapes of value-less node graphs? What about when given two
    different nodes of the same non oriented graph? The ad hoc
    [non]/dereferencing can get quite evil pretty fast.

    However, the documentation (http://golang.org/pkg/reflect/#DeepEqual)
    says the opposite: "It uses normal == equality where possible but will
    scan members of arrays, slices, maps, and fields of structs.". If it
    dereferences a pointer to a string and compare the dereferenced values
    instead then the docs are docs are not correct.

    Now I'm confused ;-)

    -j
    On Mon, Mar 11, 2013 at 8:44 AM, Doug Fawley wrote:
    On Mar 11, 2013 12:19 AM, "Jan Mercl" wrote:
    IMO the code behaves correctly:
    http://golang.org/ref/spec#Comparison_operators.
    But this is reflect.DeepEqual, not a comparison operator, so I don't think
    that necessarily applies... Likewise, your example is with ==, and I've
    already shown cases where DeepEqual does dereference-then-compare.
    Please see the above reply to Dan.

    -j

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Doug Fawley at Mar 12, 2013 at 6:28 am

    On Mon, Mar 11, 2013 at 1:03 AM, Jan Mercl wrote:

    I wonder, how DeepEqual manages cyclic data? Does
    it compare shapes of value-less node graphs? What about when given two
    different nodes of the same non oriented graph? The ad hoc
    [non]/dereferencing can get quite evil pretty fast.
    It looks like it maintains a set of visited addresses so it can
    short-circuit computations if the same appears multiple times, which also
    will stop you when cycles are encountered..

    However, the documentation (http://golang.org/pkg/reflect/#DeepEqual)
    says the opposite: "It uses normal == equality where possible but will
    scan members of arrays, slices, maps, and fields of structs.". If it
    dereferences a pointer to a string and compare the dereferenced values
    instead then the docs are docs are not correct.
    It does say that it uses == if possible, which led me to assume the same
    thing at first -- especially when coupled with my failing test case that I
    believed should have passed. Might be nice to clarify in the doc string.
    On Mon, Mar 11, 2013 at 1:07 AM, Jesse McNelis wrote:

    Still, I think the DeepEqual behavior question is valid and unresolved.
    Since the keys aren't the string values and are instead the pointers to
    the string values this would allow two maps with completely different keys
    to be considered equal. That's seriously weird.
    Not any weirder than dereferencing other pointers and comparing by value,
    except the implementation is harder. The *real *trouble comes in when the
    map keys: 1. Are pointers to non-data types (could fall back to ptr
    comparison in that case), or 2. Have duplicate data behind different
    pointers. Case 2 is really hard to solve. Consider the case:

    m1[&"hi"] = 1
    m1[&"hi"] = 2
    m2[&"hi"] = 1
    m2[&"hi"] = 2

    These are clearly equivalent, but to check this you need to compare all
    combinations of m1's keys + m2's keys. And then imagine if the maps'
    values were deep data structures instead of simple ints...it would get
    expensive to recursively compare them in all combinations.

    OK, DeepEqual is probably good the way it is...but might be nice to
    document this to prevent others from asking the same questions later.

    Thanks,
    Doug

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Doug Fawley at Mar 11, 2013 at 7:44 am

    On Mar 11, 2013 12:19 AM, "Jan Mercl" wrote:
    IMO the code behaves correctly:
    http://golang.org/ref/spec#Comparison_operators.

    But this is reflect.DeepEqual, not a comparison operator, so I don't think
    that necessarily applies... Likewise, your example is with ==, and I've
    already shown cases where DeepEqual does dereference-then-compare.
    Should DeepEqual dereference pointers and compare the dereferenced
    values instead? Consider

    type node struct { next * node }

    n := &node{}
    n.next = n

    reflect.NewDeepEqual(n, n) // don't expect this to ever return
    But DeepEqual will, since it keeps track of visited nodes...
    Using a pointer to a string _does_ save memory, but only one machine
    word. String is a value type, roughly struct{p *byte, len int}.
    Hmm, that definitely is good to know that the string buffer is not being
    copied around behind the scenes.. Even so, there's a 50% savings to be had,
    so I might try something like that dict and use an int. Thanks for the tip.

    Still, I think the DeepEqual behavior question is valid and unresolved.

    Doug

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Jesse McNelis at Mar 11, 2013 at 8:07 am

    On Mon, Mar 11, 2013 at 6:44 PM, Doug Fawley wrote:

    Hmm, that definitely is good to know that the string buffer is not being
    copied around behind the scenes.. Even so, there's a 50% savings to be had,
    so I might try something like that dict and use an int. Thanks for the tip.
    You pay for those bytes with cache misses.
    Since the speed of light isn't getting any faster
    Still, I think the DeepEqual behavior question is valid and unresolved.
    Since the keys aren't the string values and are instead the pointers to the
    string values this would allow two maps with completely different keys to
    be considered equal. That's seriously weird.

    --
    =====================
    http://jessta.id.au

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupgolang-nuts @
categoriesgo
postedMar 11, '13 at 7:03a
activeMar 12, '13 at 6:28a
posts7
users4
websitegolang.org

People

Translate

site design / logo © 2022 Grokbase