Why must a hash function be deterministic, and what breaks when it mixes in state outside the key?
answer
- the table computes, it never searches
- same key contents in, same number out
- what if the number changes between calls
- the entry is still there, just unreachable
- constant zero is deterministic and useless
basics
~20 sA hash function must return the same value for the same key contents every time, because a table locates an entry only by recomputing its bucket. Mix in a counter, a clock reading, or an object's memory address and stored entries become unreachable.
solid answer
~50 sA hash table never searches for an entry; it computes where the entry must live. Insert reduces `h(key)` to a bucket index and stores the entry there; lookup recomputes `h(key)` and probes exactly that bucket. So the hash must be a pure function of the key's contents: same contents in, same integer out, for the lifetime of the table. If the function folds in anything else — a call counter, the current time, a per-call random value, an object's identity or address rather than its contents, or the iteration order of an unordered inner collection — the second call lands somewhere else and the entry silently disappears while still occupying space. Note that determinism is only the correctness half: a function returning the constant 0 is perfectly deterministic and perfectly useless, because every key funnels into one bucket. Uniformity is the separate property that buys the expected constant-time behaviour.
go deeper
Be ready to state the rule in one sentence: same key contents, same hash value, every time. Then say what goes wrong — the entry stays in the table but no lookup ever reaches it.
Explain the mechanism, not just the rule: insert computes a slot from the hash, lookup recomputes it, and nothing else points at the entry. Name concrete sources of non-determinism such as identity-based hashing or folding in a counter.
Show you can spot the failure in review. Hashes built from mutable non-key state, from iteration order, or from raw records with padding all pass tests and then lose entries under real workloads. Say how you would detect it: unexplained duplicate keys and growing occupancy with shrinking hit rate.
Own the durability question. Decide which hash values in the system are internal to a process and which cross a boundary into storage or another service, and require the second kind to use an algorithm your team pins and versions, so an upgrade cannot silently invalidate stored values.
## What the table actually needs A hash function maps a key of arbitrary size to a fixed-width integer. A hash table then reduces that integer to a slot index — classically `index = h(key) mod m` for a table of `m` buckets — and stores the entry there. The crucial point is that a hash table has no search mechanism. A sorted structure can compare its way to an entry; a hash table cannot. It knows only one thing about where your entry lives: the number the hash function produced at insert time. Lookup, delete, and update all work by recomputing that number and going straight to the slot. Therefore the function must satisfy one absolute rule before anything else: > For the same key contents, the hash function returns the same value, every call, for as long as the entry is in the table. This is determinism. It is a *correctness* property, not a performance property. Break it and the table does not report an error — the entry is simply never found again, while continuing to consume a slot and to count toward the table's occupancy. Repeat the insert and you get a second copy of a key that already exists. This is the quietest failure mode in the whole structure. ## Where non-determinism sneaks in Candidates who have only ever used built-in hashes assume non-determinism is exotic. It is not. Real sources include: - **Folding in a counter or a clock reading.** Usually written by someone who has heard "a good hash looks random" and concluded that more randomness per call is better. - **Hashing identity rather than contents.** If the hash is derived from where an object sits in memory rather than from the bytes that define it, two separately constructed but structurally identical keys hash differently. Lookups by a freshly built key miss even though an equal key is stored. - **Hashing over an unordered inner collection by iteration order.** If a key contains a set-like member and the hash concatenates members in whatever order iteration produces, the hash changes when the internal layout changes. - **Reading uninitialised bytes.** Hashing a raw record including padding bytes that were never assigned gives different values for records that are logically equal. ## Determinism is not uniqueness, and not sufficiency Two confusions are worth naming explicitly. First, determinism does not mean collision-freedom. A hash compresses an unbounded key space into a fixed-width integer, so distinct keys *must* sometimes share a value — that is arithmetic, not a defect. The table handles it by keeping a set of colliding entries per slot and confirming the match with a full key comparison. Second, determinism alone does not make a hash usable. `h(key) = 0` never varies and never lies, yet every operation degrades to scanning a single bucket, so a table of n entries gives O(n) lookups. The full requirement is usually stated as three properties: **deterministic** (correctness), **uniform** (values spread across the output range so buckets fill evenly, which is what buys expected constant-time operations), and **cheap** (the hash runs on every single operation, so its cost sits on the critical path). ## How long must determinism hold? Within one running process, for the life of the table — that is what the table itself needs, and it is the answer expected in an interview. A stronger promise is needed the moment a hash value escapes memory: a fingerprint written to a file, a precomputed index shipped alongside data, a value compared against one produced by a different build. Built-in hashes generally make no guarantee of stability across library versions, and some runtimes deliberately vary them between processes. If you persist a hash value, pin the algorithm in code you control, write the constants down, and version them, so the value you stored last month still means the same thing today. Otherwise the stored values quietly stop matching after an upgrade — the same disappearing-entry failure, just spread across a release boundary.
- If determinism is enough for correctness, why is a hash returning a constant unacceptable?Because correctness is not the only requirement. A constant hash sends every key to one bucket, so insert, lookup, and delete all degrade to scanning a list of every entry — O(n) per operation. Uniform spread across the output range is what buys the expected constant-time behaviour a table is chosen for; determinism only guarantees you find what you stored.
- A key is a record with three fields. What makes a correct hash over it?Derive it from exactly the fields that define the key's identity, combine them in a fixed order so that two records with the same values in different fields do not collide by construction, and read no field that can vary independently of the key's contents. Every field read must itself be hashed deterministically, or the composite inherits the non-determinism.
- You want to write hash values to disk and reuse them next month. What changes?The determinism requirement widens from one process to across builds and time. Built-in hashes make no promise of stability across versions, so pin your own algorithm and constants in code you control, and version the format. If the algorithm changes, treat it as a data migration: every stored value must be recomputed, not silently reinterpreted.
It is like filing a document by a code you recompute from its title. If the code depends on what time you compute it, the document is still in the cabinet and you will never find it again.
saying these in an interview costs you the question
- Says a good hash should be random so keys spread out
- Thinks determinism means no two keys ever collide
- Derives the hash from an object's address instead of its contents
- Assumes any built-in hash value is safe to store and reuse forever
- Claims a deterministic hash is automatically a good hash