Hashing of different types with same contents

Say I have two types with hash implementations defined like this

struct A{T}
  t::T
end
Base.hash(a::A, h::UInt) = hash(a.t, h)

struct B{T}
  t::T
end
Base.hash(b::B, h::UInt) = hash(b.t, h)

I will get their hashes to agree:

julia> hash(A(1)) == hash(B(1))
true

How do I avoid this? I.e. I would like their hashes to not agree. One way would be to mix in “magical numbers”, like so:

Base.hash(a::A, h::UInt) = hash(a.t, hash(0xa, h))
Base.hash(b::B, h::UInt) = hash(b.t, hash(0xb, h))

which yields

julia> hash(A(1)) == hash(B(1))
false

Is this the preferred way?

I think the preferred way is to mix in the hash of the type itself, e.g. hash(a.t, hash(A, h)). But if you have code that relies on the hash being different then you are likely to have a bug since hash collisions are possible.

5 Likes

For sure, I’m just using it as a poor man’s checksum; I dump calculations to file with a filename that depends on the basis set employed, and have no problem that the calculation has to be redone when the hash value changes (i.e. new Julia versions). I just needed to also be able to disambiguate between different basis set types, and not just their locations.