Before my previous post gets bigger and confusing, I decided to try and implement my own custom hash() method based on the documentation and what was suggested in my previous post.
I’m aware of AutoHashEquals.jl, but I would like a basic understanding of hashing before using it.
From the documentation:
New types should implement the 2-argument form, typically by calling the 2-argument
hashmethod recursively in order to mix hashes of the contents with each other (and withh).
From my understanding of the documentation here is what I came up with:
@enum WeaponType CloseRange Reloadable
struct GameWeapon
damage::Int32
type::WeaponType
end
function ==(x::GameWeapon, y::GameWeapon)
return (x.damage === y.damage) &&
(x.type === y.type)
end
function hash(weapon::GameWeapon, h::UInt=0x12345467)
hash_of_type = hash(weapon.type,h)
hash_of_damage = hash(weapon.damage,h)
return hash((hash_of_type,hash_of_damage),h)
end
I call the 2-argument hash() method recursively to obtain the hashes for each field, create a tuple and hash that with h or as the documentation put it:
mix hashes of the contents with each other (and with
h)
main.jl:
standard_sword = GameWeapon(25,CloseRange)
println(hash(standard_sword)) # prints 272133118
- Is their anything wrong with this approach? Have I misinterpreted the documentation?
The nice part about providing the h argument is that if i had another struct with the same field it won’t produce the same hash.
struct Weapon
damage::Int32
type::WeaponType
end
function hash(weapon::Weapon, h::UInt=0x7654321)
hash_of_type = hash(weapon.type,h)
hash_of_damage = hash(weapon.damage,h)
return hash((hash_of_type,hash_of_damage),h)
end
main.jl:
standard_sword = Weapon(25,CloseRange)
println(hash(standard_sword)) # prints 1618513225
Of course none of this means I’ve written an adequate hash() method, it could all be wrong.
This maybe better in another post, but it would mean re-posting the same code again, so I’ll ask it here.
I noticed some strange behaviour with the hash() method and the h argument and I was wondering if anyone can explain.
Providing the h:
function hash(weapon::GameWeapon, h::UInt=0x12345467)
println("Provided Unsigned Int: $(h)")
end
function hash(weapon::Weapon, h::UInt=0x7654321)
println("Provided Unsigned Int: $(h)")
end
produces a different result in the println() because when I call hash(standard_sword) it generates its own unique unsigned integer and then calls the custom 2-argument hash(), overwriting the default h I provided, correct?
Provided Unsigned Int: 305419367
Provided Unsigned Int: 124076833
If I were to remove the value for the h argument and write the methods like this:
function hash(weapon::GameWeapon, h::UInt)
println("Provided Hash: $(h)")
hash_of_type = hash(weapon.type,h)
hash_of_damage = hash(weapon.damage,h)
return hash((hash_of_type,hash_of_damage),h)
end
function hash(weapon::Weapon, h::UInt)
println("Provided Hash: $(h)")
hash_of_type = hash(weapon.type,h)
hash_of_damage = hash(weapon.damage,h)
return hash((hash_of_type,hash_of_damage),h)
end
h is 0 and both methods produce the same hash value.
- Why is it that when I provide the
hvalue the following happens:
-
A unique unsigned integer is generated and used to overwrite the default
hvalue provided. -
As a result of the unique unsigned integer, a unique hash is generated, ensuring that two
structs that have the same fields won’t produce the same hash.