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

(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?