# Hash of Dict with custom type as keys

**URL:** <https://discourse.julialang.org/t/hash-of-dict-with-custom-type-as-keys/68400>\
**Category:** General Usage\
**Tags:** dictionary\
**Created:** [September 19, 2021, 8:39am UTC](https://discourse.julialang.org/t/hash-of-dict-with-custom-type-as-keys/68400 "2021-09-19T08:39:30Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Adrien](https://avatars.discourse-cdn.com/v4/letter/a/ea666f/32.png) [@Adrien](https://discourse.julialang.org/u/Adrien)\
**Post date:** [September 19, 2021, 8:39am UTC](https://discourse.julialang.org/t/hash-of-dict-with-custom-type-as-keys/68400/1 "2021-09-19T08:39:30Z")

</div>

I’m having an issue when trying to use hashes of Dict with custom type as keys. Here’s a minimal example that shows my problem:

```julia
struct My
	x::Vector{Int}
end
Base.hash(m::My)=Base.hash(m.x)	
Base.:(==)(m::My,n::My)=m.x==n.x
a=My([1,2,3])
b=My([1,2,3])
println(hash(a)==hash(b))
u=Dict(a=>1)
v=Dict(b=>1)
println(u==v)
println(hash(u)==hash(v))

```

Running this (using Julia 1.5.3) one gets that a and b have the same hash, that u and v are equal as they should but that u and v do not have the same hash, which is really confusing me. Note that this does not happen if I define a and b as just Vectors of Int rather than using a custom type. Does anyone knows why this happens and how to fix this ?

---

<div class="post-metadata">

**Author:** ![mauro3](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mauro3/32/292_2.png) [@mauro3](https://discourse.julialang.org/u/mauro3)\
**Post date:** [September 19, 2021, 8:58am UTC](https://discourse.julialang.org/t/hash-of-dict-with-custom-type-as-keys/68400/2 "2021-09-19T08:58:28Z")

</div>

You have to implement the two-arg version of hash, as per doc-string:

```julia
Base.hash(m::My, h::UInt)=Base.hash(m.x, h)

```

Not sure where it goes wrong otherwise.

See also [https://github.com/andrewcooke/AutoHashEquals.jl](https://github.com/andrewcooke/AutoHashEquals.jl)

---

<div class="post-metadata">

**Author:** ![Adrien](https://avatars.discourse-cdn.com/v4/letter/a/ea666f/32.png) [@Adrien](https://discourse.julialang.org/u/Adrien)\
**Post date:** [September 19, 2021, 9:17am UTC](https://discourse.julialang.org/t/hash-of-dict-with-custom-type-as-keys/68400/3 "2021-09-19T09:17:10Z")

</div>

Thanks ! It does fix the problem, I had seen this second argument mentioned in the doc but to be honest did not quite get what it was doing…

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [September 19, 2021, 1:06pm UTC](https://discourse.julialang.org/t/hash-of-dict-with-custom-type-as-keys/68400/4 "2021-09-19T13:06:32Z")

</div>

> [@Adrien](#):
>
> what it was doing…

when you hash a composite structure, for example, `A.a, A.b`, it will have to mix the two together:

```julia
h1 = hash(A.a, 0) #initial hash
h2 = hash(A.b, h1)

```

the second argument defaults to 0 when start with hashing the object.

---

<div class="post-metadata">

**Author:** ![CameronBieganek](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cameronbieganek/32/6915_2.png) [@CameronBieganek](https://discourse.julialang.org/u/CameronBieganek)\
**Post date:** [September 20, 2021, 2:36am UTC](https://discourse.julialang.org/t/hash-of-dict-with-custom-type-as-keys/68400/5 "2021-09-20T02:36:09Z")

</div>

Note that if you don’t mix in the name of the new type with the hash, you could end up with a situation where different types return the same hash:

```julia
struct A
    x::Vector{Int}
end

struct B
    x::Vector{Int}
end

Base.hash(a::A, h::UInt) = hash(a.x, h)
Base.hash(b::B, h::UInt) = hash(b.x, h)

```

```julia
julia> a = A([1, 2, 3]);

julia> b = B([1, 2, 3]);

julia> hash(a) == hash(b)
true

```

To avoid this, you can mix the type into the hash:

```julia
Base.hash(a::A, h::UInt) = hash(A, hash(a.x, h))
Base.hash(b::B, h::UInt) = hash(B, hash(b.x, h))

```

```julia
julia> a = A([1, 2, 3]);

julia> b = B([1, 2, 3]);

julia> hash(a) == hash(b)
false

```

Above I used the actual type objects `A` and `B` in the hash. You could use symbols like `:A` and `:B` instead. I’m not sure if there are any reasons to prefer symbols over type objects, or vice versa, when constructing the hash.
