The hash code is used in many data-structures and algorithms to identify objects that might be equal.
Therefore, the precise semantic of hash
is highly linked with the semantic of ==
and the only law of hash
is that a == b implies a.hash == b.hash
.
assert (1+1).hash == 2.hash
assert 1.to_s.hash == "1".hash
hash
(like ==
) might not be constant on some objects over time because of their evolution.
var a = [1]
var b = [1]
var c = [1,2]
assert a.hash == b.hash
a.add 2
assert a.hash == c.hash
A specific redefinition of ==
should usually be associated with a specific redefinition of hash
.
Note that, unfortunately, a correct definition of hash
that is lawful with ==
is sometime tricky
and a cause of bugs.
Without redefinition, hash
is based on the object_id
of the instance.
# The hash code of the object.
#
# The hash code is used in many data-structures and algorithms to identify objects that might be equal.
# Therefore, the precise semantic of `hash` is highly linked with the semantic of `==`
# and the only law of `hash` is that `a == b implies a.hash == b.hash`.
#
# ~~~
# assert (1+1).hash == 2.hash
# assert 1.to_s.hash == "1".hash
# ~~~
#
# `hash` (like `==`) might not be constant on some objects over time because of their evolution.
#
# ~~~
# var a = [1]
# var b = [1]
# var c = [1,2]
# assert a.hash == b.hash
# a.add 2
# assert a.hash == c.hash
# # There is a very high probability that `b.hash != c.hash`
# ~~~
#
# A specific redefinition of `==` should usually be associated with a specific redefinition of `hash`.
# Note that, unfortunately, a correct definition of `hash` that is lawful with `==` is sometime tricky
# and a cause of bugs.
#
# Without redefinition, `hash` is based on the `object_id` of the instance.
fun hash: Int do return object_id
lib/core/kernel.nit:196,2--224,34
# A hashcode based on the hashcode of the keys and the values.
#
# ~~~
# var a = new HashMap[String, Int]
# var b = new ArrayMap[Object, Numeric]
# a["one"] = 1
# b["one"] = 1
# assert a.hash == b.hash
# ~~~
redef fun hash
do
var res = length
for k, v in self do
if k != null then res += k.hash * 7
if v != null then res += v.hash * 11
end
return res
end
lib/core/collection/abstract_collection.nit:664,2--681,4
# Because of the law between `==` and `hash`, `hash` is redefined to be the sum of the hash of the elements
redef fun hash
do
# The 17 and 2/3 magic numbers were determined empirically.
# Note: the standard hash functions djb2, sbdm and fnv1 were also
# tested but were comparable (or worse).
var res = 17 + length
for e in self do
res = res * 3 / 2
if e != null then res += e.hash
end
return res
end
lib/core/collection/abstract_collection.nit:1021,2--1033,4
# var a = new Range[Int](10, 15)
# assert a.hash == 455
# var b = new Range[Int].without_last(10, 15)
# assert b.hash == 432
redef fun hash do
# 11 and 23 are magic numbers empirically determined to be not so bad.
return first.hash * 11 + last.hash * 23
end
lib/core/collection/range.nit:127,2--134,4
redef fun hash do
return derive_to_map.hash
end
lib/deriving/deriving.nit:114,2--116,4
redef fun hash do return code_point
lib/core/kernel.nit:910,2--36
# Because of the law between `==` and `hash`, `hash` is redefined to be the sum of the hash of the elements
redef fun hash
do
# 23 is a magic number empirically determined to be not so bad.
var res = 23 + length
# Note: the order of the elements must not change the hash value.
# So, unlike usual hash functions, the accumulator is not combined with itself.
for e in self do
if e != null then res += e.hash
end
return res
end
lib/core/collection/abstract_collection.nit:493,2--504,4