Go

This compiles. Why does it panic at runtime?

Question 508HardGo 1.22 to 1.25
var a, b any = []int{1}, []int{1}
fmt.Println(a == b)
// panic: runtime error: comparing uncomparable type []int

seen := map[any]bool{}
seen[[]int{1}] = true
// panic: runtime error: hash of unhashable type []int

Comparing two interface values is allowed at compile time. At runtime, Go first compares the dynamic types. If they are the same and that type is not comparable (slice, map, func, or a struct or array containing one), it panics. Using such a value as a key in a map[any]T panics for the same reason: it has to be hashed.

A subtle point: if the dynamic types differ, the result is simply false with no panic, so the bug appears only for some inputs. This regularly hits caches keyed by any, dedup helpers, and hand-written err == target checks on custom error types that contain slices. errors.Is itself is safe, because it uses == only when the target's type is comparable. For such a type it simply never matches, so give the error an Is method.

With generics, the comparable constraint used to exclude interface types. Since Go 1.20, interfaces satisfy comparable, so func Eq[T comparable](a, b T) bool called with any can panic in the same way. Safer options: reflect.DeepEqual, slices.Equal, or a type switch that rejects kinds that cannot be compared.

More on Tricky Output & Code-Review Puzzles

All 38 Tricky Output & Code-Review Puzzles questions