Go

Why is err != nil true here even though the function returned a nil pointer?

Question 488HardGo 1.22 to 1.25
type MyErr struct{ msg string }

func (e *MyErr) Error() string { return "myerr" }

func do(fail bool) error {
    var p *MyErr
    if fail {
        p = &MyErr{"bad"}
    }
    return p // BUG
}

func main() {
    err := do(false)
    fmt.Println(err == nil)   // false
    fmt.Printf("%T %v\n", err, err) // *main.MyErr myerr
}

An interface value is a pair (dynamic type, dynamic value). It equals nil only when both are nil. Returning a typed nil pointer as error gives (*MyErr, nil). The type half is set, so the comparison is false. Callers then treat it as a failure, and a method that dereferences the receiver will panic.

Fix: return the literal nil on success and never pass a concrete error type through an error return:

func do(fail bool) error {
    if fail {
        return &MyErr{"bad"}
    }
    return nil
}

The same trap shows up with var r io.Reader = (*bytes.Buffer)(nil). To check for a typed nil you need reflection (reflect.ValueOf(x).IsNil()), which is a design smell. The interviewer wants the two-word model of interfaces and the rule "return interface types as untyped nil".

More on Tricky Output & Code-Review Puzzles

All 38 Tricky Output & Code-Review Puzzles questions