Nil Map Scenario
Fast recall
Quick revision
Core answer
Whether you understand Nil Map Scenario beyond memorized syntax.
Giving a definition without explaining a practical trade-off.
Connect the concept to a small production example and state its complexity or failure mode.
Interview-ready guide
Interview answer
The panic, reproduced:
var m map[string]int
// Reads work — nil map reads return zero values
v := m["key"] // 0 — no error, no panic
_, ok := m["key"] // (0, false) — safe
// WRITE panics
m["key"] = 1
// panic: assignment to entry in nil mapThe root cause: a map value is a pointer to the hash-table structure. var m is nil — the pointer points at nothing. A read of 'nothing' honestly answers 'not there' (the zero value). A write to 'nothing' has nowhere to put the entry — the runtime refuses with a panic.
The fix — make the map:
m := make(map[string]int) // empty, write-ready
m := map[string]int{} // literal — same, write-ready
m := map[string]int{"k": 1} // with initial valuesThe classic causes:
- 1Declared var m map[...]... and forgot the make
- 2A struct with a map field not initialized in the constructor (the zero value struct has a nil map)
- 3Passing a nil map into a function that populates it — the function can't fix the caller's nil (make inside doesn't reassign the caller's variable)
The fix pattern for the struct case: initialize in the constructor or immediately:
type Cache struct {
data map[string]string
}
func NewCache() *Cache {
return &Cache{data: make(map[string]string)} // NEVER nil
}Nil Map Scenario
Direct Answer
var m map[string]int is nil — reads work (zero values), WRITES panic. The fix: m = make(map[string]int) or a literal m := map[string]int{}. Every write needs the map initialized.
Deep Dive & Architecture
Why the asymmetry with slices: a nil slice can be appended (append allocates the backing storage — the header IS the value). A nil map cannot be written — the map's structure (hash table, buckets, seeds) must be created by make; there's no 'lazily create on write' path because the map is already a pointer (the write would need to reassign the pointer, which Go's assignment semantics won't do through a map variable).
The function-parameter trap, expanded: populateMap(m map[string]int) with a nil m: making a NEW map inside the function creates a local — the caller's nil stays nil. The correct API: return the map (func makeMap() map[string]int), or take a *map, or (the Go-idiomatic form) the function makes and returns: callers compose.
The read-on-nil design rationale: 'total functions' — a read from any map (nil or empty) returns a value. The zero-value read lets accumulation code (m[k]++ — reads then writes) work on an EMPTY map, with the nil case being the single excluded state (the write panic is the deliberate loud failure).
Common Mistakes & Pitfalls
Giving a definition without explaining a practical trade-off.
Check your understanding
Answer these without looking back at the article.
- How would you compare Nil Map Scenario with an alternative?
- What is a common mistake when using Nil Map Scenario?
- When would you use Nil Map Scenario in a real project?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.