Map keys
Map keys
[public] class Map<KT: impl Hash, impl Equals, VT> { }A key type has to satisfy both bounds. hash() chooses the bucket and equals
resolves collisions during probing.
What works out of the box
string, number, bool, and char all implement both, so the common cases
need nothing. string hashes with FNV-1a over its bytes; number folds its full
bit pattern, collapsing negative zero.
Using your own type as a key
Two things have to be true, and only one of them is enforced.
impl Equals is required and checked. Object provides no default equality,
so the bound fails until you write it.
hash() is inherited and almost certainly wrong. Object implements Hash
returning a constant zero, so any class satisfies the impl Hash bound
immediately. The map still works, but every key lands in one bucket and lookups
degrade to a linear scan.
So a usable key type overrides both:
[public] class Point impl Hash, Equals<Point> {
x: number
y: number
[public] fn hash() => number {
return this.x.hash() + this.y.hash() * 31
}
[public] fn equals(other: Point) => bool {
return this.x == other.x && this.y == other.y
}
}The usual invariant applies and is not enforced: two keys that compare equal must hash equal, or lookups will miss.