Stdlib Generic Packages — Find the Bug¶
How to use¶
Each problem shows a snippet that compiles or appears to compile. Read it carefully and answer: 1. What is the bug? 2. How would you fix it? 3. Could a stdlib helper have prevented it?
Solutions are at the end.
Bug 1 — assuming maps.Keys returns sorted¶
m := map[string]int{"b": 2, "a": 1, "c": 3}
keys := slices.Collect(maps.Keys(m))
fmt.Println(keys) // expected [a b c]
Hint: Map iteration order.
Bug 2 — slices.Compact without sorting¶
Hint: What does Compact actually remove?
Bug 3 — slices.Min on possibly empty slice¶
Hint: Check the panics list.
Bug 4 — slices.Insert return ignored¶
Hint: What does Insert return?
Bug 5 — slices.Delete return ignored¶
Hint: Same family as Bug 4.
Bug 6 — BinarySearch on unsorted slice¶
s := []int{5, 1, 3, 2}
idx, ok := slices.BinarySearch(s, 3)
fmt.Println(idx, ok) // expected 2, true
Hint: Precondition.
Bug 7 — wrong comparator return type¶
Hint: What type does the comparator return?
Bug 8 — cmp.Or evaluates all arguments¶
The user expected: "stop calling functions when one returns non-zero". What actually happens?
Hint: Argument evaluation order in Go.
Bug 9 — slices.Equal and NaN¶
a := []float64{1, math.NaN()}
b := []float64{1, math.NaN()}
fmt.Println(slices.Equal(a, b)) // expected true
Hint: NaN == NaN semantics.
Bug 10 — missing cmp.Compare result handling¶
Hint: What about equal ages? What does pdqsort do then?
Bug 11 — assuming slices.Sort is stable¶
type Event struct{ Time int; Order int }
slices.SortFunc(events, func(a, b Event) int {
return cmp.Compare(a.Time, b.Time)
})
// expected: events with the same Time keep their original Order
Hint: Read the godoc.
Bug 12 — maps.Clone for deep copy¶
type Box struct{ items []int }
m := map[string]Box{"a": {items: []int{1, 2}}}
cp := maps.Clone(m)
cp["a"].items[0] = 99
fmt.Println(m["a"].items[0]) // expected 1, got 99
Hint: Shallow copy.
Bug 13 — slices.Compact aliasing¶
Hint: Same backing array.
Bug 14 — using cmp.Compare on non-Ordered¶
Hint: What does cmp.Compare accept?
Bug 15 — wrong index argument to slices.Insert¶
Hint: Valid index range.
Bug 16 — cmp.Or with default zero string¶
The user wrote:
…and the result was "supplied". Then they extended:
…and got "supplied" as expected. But:
…returned " " instead of "fallback". Why?
Hint: What counts as "zero"?
Solutions¶
Bug 1 — fix¶
Map iteration order is randomized. Sort explicitly:
Bug 2 — fix¶
Compact removes only adjacent duplicates. Sort first:
Bug 3 — fix¶
Guard the empty case:
Bug 4 — fix¶
Insert returns a (possibly reallocated) slice. Reassign:
Bug 5 — fix¶
Same as Bug 4:
Bug 6 — fix¶
Sort first:
Bug 7 — fix¶
The comparator must return int, not bool:
Bug 8 — fix¶
Function arguments are evaluated before cmp.Or runs. All three calls fire. To short-circuit, write the chain explicitly:
val := loadFromCache()
if val == "" { val = loadFromDisk() }
if val == "" { val = loadFromNetwork() }
Bug 9 — explanation¶
slices.Equal uses ==, and NaN == NaN is false by IEEE-754. So slices.Equal(a, b) is false even though the slices look equal. Use slices.EqualFunc with custom NaN-aware equality if needed.
Bug 10 — fix¶
The comparator returns 1 for equal ages, telling pdqsort that a > b. Sorting becomes incorrect. Always handle equality:
Bug 11 — fix¶
slices.SortFunc is unstable. Use slices.SortStableFunc:
Bug 12 — explanation¶
maps.Clone is shallow. The Box.items slice is shared between m and cp. Mutating cp["a"].items[0] mutates the shared backing array. Write a deep clone manually:
Bug 13 — explanation¶
Compact returns a slice that aliases the input. out[0] = 99 mutates s[0]. To avoid: out := slices.Clone(slices.Compact(slices.Clone(s))).
Bug 14 — fix¶
cmp.Compare requires cmp.Ordered. For struct types, write the comparator yourself:
Bug 15 — fix¶
The valid range is 0 <= i <= len(s). For len 4 the max valid index is 4 (append at end), not 5:
Bug 16 — explanation¶
cmp.Or returns the first non-zero. For strings, the zero is "". " " (space) is not zero, so it is returned. If you want "first non-empty after trimming", write your own:
Lessons¶
Patterns from these bugs:
Compactonly removes adjacent duplicates (Bug 2) — sort first.- Map iteration is randomized (Bug 1) — sort if you need order.
Min/Max/Insert/Deletepanic on bad input (Bugs 3, 15) — guard.- Mutation APIs return a new slice header (Bugs 4, 5) — reassign.
BinarySearchrequires sorted input (Bug 6) — precondition.- Comparator must return
int, notbool(Bug 7) — usecmp.Compare. - All arguments to
cmp.Orare evaluated (Bug 8) — no short-circuit. NaN != NaN(Bug 9) —slices.Equaldoes not handle this.- Comparators must handle equality (Bug 10) — return
0, not1. SortFuncis unstable (Bug 11) — useSortStableFuncwhen stability matters.- Clone is shallow (Bug 12) — write deep clone manually.
Compactaliases the input (Bug 13) —Clonefirst if needed.cmp.Comparerequirescmp.Ordered(Bug 14) — custom comparator for structs.cmp.Or"zero" is the type's zero value (Bug 16) —" "is not zero.
A senior engineer reads stdlib godoc carefully — every panic, every "must be sorted", every "shallow copy" is documented and easy to miss until it bites in production.