Go

Type switch puzzle: what does describe return for each input?

Question 514HardGo 1.22 to 1.25
func describe(x any) string {
    switch v := x.(type) {
    case nil:
        return "nil"
    case int, int64:
        // return fmt.Sprint(v + 1) // compile error: v is any here
        return fmt.Sprintf("integer %v %T", v, v)
    case error:
        return "error " + v.Error()
    case fmt.Stringer:
        return "stringer " + v.String()
    default:
        return fmt.Sprintf("other %T", v)
    }
}

var p *int
fmt.Println(describe(nil))              // ?
fmt.Println(describe(int64(5)))         // ?
fmt.Println(describe(p))                // ?
fmt.Println(describe(time.Second))      // ?
fmt.Println(describe(errors.New("x")))  // ?

Output:

nil
integer 5 int64
other *int
stringer 1s
error x

Points the interviewer is checking:

case nil matches only a nil interface. A typed nil pointer such as p has dynamic type *int, so it falls to default. This is the same typed-nil trap as with error.

In a case that lists one type, v has that type. In a case that lists several types (case int, int64), and in default and case nil, v has the type of the switch expression, here any. That is why v + 1 does not compile there.

Cases are tried in source order, and the first match wins. time.Duration has a String method but no Error method, so it reaches the Stringer case. A type that implements both error and Stringer always stops at error, because that case comes first. Put the more specific interfaces first. fmt follows the same rule: it prefers Error() over String() when formatting with %v.

More on Tricky Output & Code-Review Puzzles

All 38 Tricky Output & Code-Review Puzzles questions