# Properly implement Base.hash() for custom type

**URL:** <https://discourse.julialang.org/t/properly-implement-base-hash-for-custom-type/61951>\
**Category:** General Usage\
**Created:** [May 27, 2021, 5:56pm UTC](https://discourse.julialang.org/t/properly-implement-base-hash-for-custom-type/61951 "2021-05-27T17:56:27Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![anon60034542](https://avatars.discourse-cdn.com/v4/letter/a/90ced4/32.png) [@anon60034542](https://discourse.julialang.org/u/anon60034542)\
**Post date:** [May 27, 2021, 5:56pm UTC](https://discourse.julialang.org/t/properly-implement-base-hash-for-custom-type/61951/1 "2021-05-27T17:56:27Z")

</div>

Consider the following code:

```julia
@enum WeaponType CloseRange Reloadable

struct GameWeapon
    damage::Int32
    type::WeaponType
end

```

Reading the [documentation](https://docs.julialang.org/en/v1/base/base/#Base.hash), it says:

> New types should implement the 2-argument form, typically by calling the 2-argument `hash` method recursively in order to mix hashes of the contents with each other (and with `h` ).

Is this how you would implement the `Base.hash()` based on the documentation?

```julia
function ==(x::GameWeapon, y::GameWeapon)
    return (x.damage === y.damage) &&
           (x.type === y.type)
end

function hash(weapon::GameWeapon, h::UInt = 0x01234567)
    hash_of_weapon_attribs = hash(hash(weapon.damage,h),hash(weapon.type,h))
    return hash(hash_of_weapon_attribs,h)
end

```

If not, how would you do it?

---

<div class="post-metadata">

**Author:** ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)\
**Post date:** [May 27, 2021, 6:02pm UTC](https://discourse.julialang.org/t/properly-implement-base-hash-for-custom-type/61951/2 "2021-05-27T18:02:14Z")

</div>

I don’t think there’s any reason to supply a default for the second argument (the base `hash(x::Any)` method in `Base` will do this for you). And you can probably simplify the implementation a bit to something more like:

```julia
function hash(weapon::GameWeapon, h::UInt)
  hash(weapon.type, hash(weapon.damage, h))
end

```

---

<div class="post-metadata">

**Author:** ![jzr](https://avatars.discourse-cdn.com/v4/letter/j/eb9ed0/32.png) [@jzr](https://discourse.julialang.org/u/jzr)\
**Post date:** [May 27, 2021, 6:08pm UTC](https://discourse.julialang.org/t/properly-implement-base-hash-for-custom-type/61951/3 "2021-05-27T18:08:03Z")

</div>

This implementation seems very generic. Is there a sugar that defines this implementation for a given struct?

---

<div class="post-metadata">

**Author:** ![anon60034542](https://avatars.discourse-cdn.com/v4/letter/a/90ced4/32.png) [@anon60034542](https://discourse.julialang.org/u/anon60034542)\
**Post date:** [May 28, 2021, 5:01pm UTC](https://discourse.julialang.org/t/properly-implement-base-hash-for-custom-type/61951/4 "2021-05-28T17:01:57Z")

</div>

In the documentation it says:

> New types should implement the 2-argument form, typically by calling the 2-argument `hash` method **recursively**

Shouldn’t `weapon.type` be hashed as well?

```julia
function hash(weapon::GameWeapon, h::UInt)
  return hash(hash(weapon.type,h), hash(weapon.damage, h))
end

```

---

<div class="post-metadata">

**Author:** ![fredrikekre](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fredrikekre/32/1688_2.png) [@fredrikekre](https://discourse.julialang.org/u/fredrikekre)\
**Post date:** [May 28, 2021, 5:54pm UTC](https://discourse.julialang.org/t/properly-implement-base-hash-for-custom-type/61951/5 "2021-05-28T17:54:39Z")

</div>

> [@jzr](#):
>
> This implementation seems very generic. Is there a sugar that defines this implementation for a given struct?

There is [AutoHashEquals.jl](https://github.com/andrewcooke/AutoHashEquals.jl).

> [@anon60034542](#):
>
> Shouldn’t `weapon.type` be hashed as well?

It is hashed, just not with `h` as seed but instead using the result of `hash(weapon.damage, h)` as the seed.

FWIW, AutoHashEquals.jl would define:

```julia
function Base.hash(g::GameWeapon, h::UInt)
    hash(g.type, hash(g.damage, hash(:GameWeapon, h)))
end

```

---

<div class="post-metadata">

**Author:** ![anon60034542](https://avatars.discourse-cdn.com/v4/letter/a/90ced4/32.png) [@anon60034542](https://discourse.julialang.org/u/anon60034542)\
**Post date:** [May 28, 2021, 5:59pm UTC](https://discourse.julialang.org/t/properly-implement-base-hash-for-custom-type/61951/6 "2021-05-28T17:59:09Z")

</div>

Is writing it the way [AutoHashEquals.jl](https://github.com/andrewcooke/AutoHashEquals.jl) does any better than what [rdeits](https://discourse.julialang.org/t/properly-implement-base-hash-for-custom-type/61951/2) suggested? I’m not criticizing his answer, I just want a better understanding of which method is better.

---

<div class="post-metadata">

**Author:** ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)\
**Post date:** [May 28, 2021, 6:00pm UTC](https://discourse.julialang.org/t/properly-implement-base-hash-for-custom-type/61951/7 "2021-05-28T18:00:46Z")

</div>

Hashing the type too (the way `AutoHashEquals` does) is probably a good idea, since it will prevent hash collisions between two different structs that happen to have the same fields. On reflection, I’d probably recommend what @fredrikekre wrote over what I posted above.

---

<div class="post-metadata">

**Author:** ![anon60034542](https://avatars.discourse-cdn.com/v4/letter/a/90ced4/32.png) [@anon60034542](https://discourse.julialang.org/u/anon60034542)\
**Post date:** [May 28, 2021, 6:03pm UTC](https://discourse.julialang.org/t/properly-implement-base-hash-for-custom-type/61951/8 "2021-05-28T18:03:25Z")

</div>

Out of curiosity, is there anything wrong with the way I did the `hash()`? The part of recursive may have confused me.

I see the problem, just as you mentioned.

```julia
@enum WeaponType CloseRange Reloadable

struct GameWeapon
    damage::Int32
    type::WeaponType
end

struct Weapon
    damage::Int32
    type::WeaponType
end

```

```julia
standard_sword = GameWeapon(25,CloseRange)
println(hash(standard_sword))

standard_sword = Weapon(25,CloseRange)
println(hash(standard_sword))

```

Both of these produce the same hash code. Given that they’re different `struct`’s they should produce different hash codes, correct?

---

<div class="post-metadata">

**Author:** ![fredrikekre](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fredrikekre/32/1688_2.png) [@fredrikekre](https://discourse.julialang.org/u/fredrikekre)\
**Post date:** [May 28, 2021, 6:19pm UTC](https://discourse.julialang.org/t/properly-implement-base-hash-for-custom-type/61951/9 "2021-05-28T18:19:30Z")

</div>

Not necessarily, it just decreases the risk of hash collisions. Even though they have the same hash you can use both as separate keys in `Dict` for example

```julia
julia> g1 = GameWeapon(25,CloseRange);

julia> g2 = Weapon(25,CloseRange);

julia> hash(g1)
0x4f2c71de34f6c410

julia> hash(g2)
0x4f2c71de34f6c410

julia> d = Dict();

julia> d[g1] = "g1";

julia> d[g2]
ERROR: KeyError: key Weapon(25, CloseRange) not found

julia> d[g2] = "g2";

julia> d
Dict{Any, Any} with 2 entries:
  GameWeapon(25, CloseRange) => "g1"
  Weapon(25, CloseRange) => "g2"

```

* * *

There is also for example

```julia
julia> hash(1)
0x5bca7c69b794f8ce

julia> hash(1.0)
0x5bca7c69b794f8ce

```

although this is an `Int` and a `Float64`. However, in this case you can’t have them as two keys in a `Dict` which is a bit weird, not sure what is up with that.

```julia
julia> d = Dict();

julia> d[1] = "Int"
"Int"

julia> d[1.0] # !!!
"Int"

```

---

<div class="post-metadata">

**Author:** ![anon60034542](https://avatars.discourse-cdn.com/v4/letter/a/90ced4/32.png) [@anon60034542](https://discourse.julialang.org/u/anon60034542)\
**Post date:** [May 28, 2021, 6:27pm UTC](https://discourse.julialang.org/t/properly-implement-base-hash-for-custom-type/61951/10 "2021-05-28T18:27:13Z")

</div>

Ah! Thanks for the explanation.

My problem here is that I was confused about this part:

> New types should implement the 2-argument form, typically by calling the 2-argument `hash` method  
> **recursively** in order to mix hashes of the contents with each other (and with `h` ).

I don’t mind using [AutoHashEquals.jl](https://github.com/andrewcooke/AutoHashEquals.jl), but I would like to understand for myself how to properly implement `Base.hash()` according to the documentation.

The part I misunderstood was the recursive.

It seems to produce a unique hash, `AutoHashEquals.jl` combines the `struct` name as a symbol along with the required fields, correct?

---

<div class="post-metadata">

**Author:** ![fredrikekre](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fredrikekre/32/1688_2.png) [@fredrikekre](https://discourse.julialang.org/u/fredrikekre)\
**Post date:** [May 28, 2021, 6:44pm UTC](https://discourse.julialang.org/t/properly-implement-base-hash-for-custom-type/61951/11 "2021-05-28T18:44:52Z")

</div>

> [@anon60034542](#):
>
> My problem here is that I was confused about this part:

> [@anon60034542](#):
>
> The part I misunderstood was the recursive.

It would be great to add an example to make this clear then, do you want to contribute with that? [Here](https://github.com/JuliaLang/julia/blob/5dbf45a2997acd26e0f72abaa320c9d0d54956a1/base/hashing.jl#L5-L19) is the docstring.

* * *

> [@anon60034542](#):
>
> It seems to produce a unique hash, `AutoHashEquals.jl` combines the `struct` name as a symbol along with the required fields, correct?

Yes, but there is still no guarante it will be a unique value, e.g.

```julia
module A
struct Foo
    x::Int
end
end

module B
struct Foo
    x::Int
end
end

```

would give the same hash for `A.Foo(1)` and `B.Foo(1)`. I don’t think it matters that much though.

---

<div class="post-metadata">

**Author:** ![anon60034542](https://avatars.discourse-cdn.com/v4/letter/a/90ced4/32.png) [@anon60034542](https://discourse.julialang.org/u/anon60034542)\
**Post date:** [May 28, 2021, 7:32pm UTC](https://discourse.julialang.org/t/properly-implement-base-hash-for-custom-type/61951/12 "2021-05-28T19:32:35Z")

</div>

> [@fredrikekre](#):
>
> It would be great to add an example to make this clear then, do you want to contribute with that? [Here](https://github.com/JuliaLang/julia/blob/5dbf45a2997acd26e0f72abaa320c9d0d54956a1/base/hashing.jl#L5-L19) is the docstring.

It’s funny you mention that, because I [suggested](https://discourse.julialang.org/t/would-it-be-possible-to-update-the-documentation-to-include-how-to-implement-isequal-and-hash/53518) it a few months ago 😃 .

I’m still learning so I don’t think that I’d be able to produce an accurate example. Perhaps someone with deep knowledge of Julia might update the documentation.
