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
hash
method 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
h
value the following happens:
-
A unique unsigned integer is generated and used to overwrite the default
h
value provided. -
As a result of the unique unsigned integer, a unique hash is generated, ensuring that two
struct
s that have the same fields won’t produce the same hash.