What must Hashable guarantee, and why does iteration order change between launches?

2.1.2 · L2 · Interview

Predict first

How many elements does the set hold?

struct User: Hashable {
    let id: Int
    let name: String
    static func == (a: User, b: User) -> Bool { a.id == b.id }
    func hash(into h: inout Hasher) { h.combine(id) }
}

print(Set([User(id: 1, name: "A"), User(id: 1, name: "B")]).count)
  • 1
  • 2

Predict first

What does this print?

var counts: [Character: Int] = [:]
for c in "hello" { counts[c, default: 0] += 1 }
print(counts["l"]!)
  • 1
  • 2
  • Crash

Mental model. A hash is a coat-check number. Two identical coats must get the same number, but two different coats may share one.

The contract is one rule: equal values must produce the same hash. The reverse is allowed (different values can collide). If == and hash(into:) disagree, a value can sit in a Set or Dictionary and still not be found.

Swift seeds its hash function randomly for every process, so the same set iterates in a different order each launch. That is deliberate: it stops code depending on order and blunts hash-flooding attacks. Never persist hashValue. For reproducible debugging or tests, set the SWIFT_DETERMINISTIC_HASHING environment variable.

== and the hash both look only at id, so the two users are equal and hash alike. If the hash also combined name, the contract would break.

The default: subscript reads 0 for a missing key and writes back after the increment, so you never unwrap or branch.

Common traps

  • Hashing a field that == ignores. Equal values then land in different buckets and a lookup misses.
  • Mutating a key after inserting it. With a class key, changing a hashed field strands the entry. Hash only immutable state.

They might follow up with

  • How do you implement Hashable by hand? Feed the same fields == compares into hasher.combine, in hash(into:).
  • Why not store hashValue in a database? It changes per process, so yesterday’s numbers mean nothing today.

Related questions

  • 2.1.1 Array, Set or Dictionary: how do you choose, and what does each operation cost?
  • 2.9.5 How does equality work for NSObject subclasses, and why do two “equal” objects stay distinct in a Set?

← Array, Set or Dictionary: how do you choose, and what does each…   When is the standard library not enough, and what does… →