Proposal Details
Ignoring certain errors is a relatively common operation.
Some examples include:
var tr *tar.Reader = ...
for {
th, err := tr.Next()
if err := nil {
if err == io.EOF {
return nil
}
return err
}
...
}
var tx *sql.Tx = ...
if err := tx.QueryRow(ctx, query, &res); err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil
}
return err
}
... // use res
I propose the addition of the following helper function:
// Ignore returns nil if err matches any error in targets,
// otherwise it returns err as is.
func Ignore(err error, targets error...) error {
for _, target := range targets {
if Is(err, target) {
return nil
}
}
return err
}
While this signature doesn't statically prevent accidental swapping of the arguments, it follows a similar pattern as errors.Is
, which has exactly the same problem.
With this helper, the above examples could be simplified as:
var tr *tar.Reader = ...
for {
th, err := tr.Next()
if err := nil {
return errors.Ignore(err, io.EOF)
}
...
}
var tx *sql.Tx = ...
if err := tx.QueryRow(ctx, query, &res); err != nil {
return errors.Ignore(err, sql.ErrNoRows)
}
... // use res
Some more evidence of the utility of this: * cmd/gofmt: return a proper error for empty Go files
Comment From: gabyhelp
Related Issues
- proposal: dynamic ignored error detector #40776 (closed)
- proposal: io: add NoEOF to convert EOF to ErrUnexpectedEOF #74265
- proposal: Go 2: error handling: try statement with handler #56165 (closed)
- proposal: spec: try-handle keywords for reducing common error handling boilerplate #73376 (closed)
- proposal: Go 2: error handling with magic .handleErr() method #56126 (closed)
(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)
Comment From: eikemeier
Depending on the error one might continue processing (EOF
just meaning “reached the end”) or cut processing short (EOF
meaning “no data”), which is context dependent, but not considered by this API.
For example I might want to further process the files extracted from tar, while just returning from the database query wrapper.
Also, the examples you shared use equality to compare to sentinel errors, which is fast but needs API guarantees you only have with few functions.
errors.Is(err, target error bool
traverses err's tree, so you would traverse the tree multiple times - not sure whether this is efficient, especially when the sentinels are not found, resulting in multiple searches.
Comment From: earthboundkid
errors.Is(err, target error bool
traverses err's tree, so you would traverse the tree multiple times - not sure whether this is efficient, especially when the sentinels are not found, resulting in multiple searches.
Can we inline the look up so that it's semantically equivalent, but potentially a little faster?