Description
background
A long standing problem with error handling, but really checking nil
ness of interface variables, is typed nils:
var p *MyError = nil
if bad() {
p = ErrBad
}
return p // Will always return a non-nil error.
description
Since we already introduced a function than handles error comparisons, errors.Is
, we could resolve this edge case by checking both err == nil
and underlying value nil
ness:
var err error = (*MyError)(nil)
switch {
case err == nil:
// false
case errors.Is(err, nil):
// true
}
costs
This will make errors.Is
more complex, and meant that developers should eschew err != nil
in favour of !errors.Is(err, nil)
. At the same time, we already suggest errors.Is(err, ErrBad)
over err == ErrBad
, so this would serve to make the language more consistent.
alternatives
It may also be confusing that this only applies for nil
able types. We could instead define that all default value types are nil
:
type MyError struct{}
func (MyError) Error() string { return "" }
func main() {
_ = errors.Is(MyError{}, nil) // == true
}
Since every implementer may want to handle the nil case differently, we could instead upon the implementation of interface{ Is(error) bool }
to determine what should be done. This is a larger topic so see #40673. That being said, for errors that are implemented upon types, e.g. func (MyError) Error() string
, we may need to have a standard resolution for (*MyError)(nil)
. Furthermore, if #40673 is accepted, we should allow it to override any defaults suggested here.
Since we are flattening nil
ness in the err
parameter, should we allow the same in the target
, errors.Is(err, (*MyError)(nil))
?