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?
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
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:
function hash(weapon::GameWeapon, h::UInt)
hash(weapon.type, hash(weapon.damage, h))
end
Is writing it the way AutoHashEquals.jl does any better than what rdeits suggested? I’m not criticizing his answer, I just want a better understanding of which method is better.
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.
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> 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"
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.
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, 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?
It’s funny you mention that, because I suggested 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.