New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
proposal: Go 2: universal WrapError type #36994
Comments
Though not a language change, following the new questionaire for language changes in the hope of making this easier to review.
Expert, ~6y using it.
C++ and Java, though neither at the level of Go.
No meaningful change.
Go team proposals: My own proposals:
Anyone embracing wrapped errors trying to do anything but the bare minimum with them. For example doing not standard error printing (previously, I myself had to do JSON error encoding of wrapped errors) or wanting stack frames on their errors.
No language change.
(in terms of standard library)
Very little change for the average user of wrapped erorrs. Primarily from: if err := nil {
return myError{myData: ..., e: err}
} to if err := nil {
return errors.Wrap(err, myError{myData: ...})
} Richer examples in this repo and the various variants in the extensions directory within it.
No language change.
Primarily vet, to highlight error types with an
None expected.
The optimize extension actually shows it can be made to be more efficient than the current implementation, particularly for longer chains of wrapped errors. Adding stack frames would have a cost, though.
See this repo and the various extensions. The implementation is actually very small.
It doesn't.
N/A
Performance is not a goal.
Yes, it targets error handling directly. It changes the definition of a wrapped error.
No |
We want a wrapped error to be defined by an interface so existing errors can conform. By requiring errors to be instances of |
But by having wrapped errors defined by an interface the other advanced features can't be delivered. The cost of not doing anything is not negligible by any means.
Best we can do is mitigate the damage. For that, the most urgent thing is to introduce the |
I have released a library, zerrors that implements the ideas exposed above, namely:
The library is performant, in fact the frameless form is more so that The library uses the idea of a universal wrap error type outlines in this proposal. |
Any project can start using their own new error type. It's clear that different Go programs have different needs for error types. The idea of adding new features to a standard error type runs directly counter to that. We want the As @jba notes, the transition from It seems better to provide this in a separate package, as you've already done. |
Of course - while the universal wrapper type holds the wrapping functionality, it may carry any custom error. That is already in zerrors:
To clarify it is not
I understand this has to start like this, as a separate library, and prove itself first. But while it remains outside the standard library and |
I have released zerrors@v0.2.0. WRT error formatting & stack traces: a single error produced by zerrors can be serialised in arbitrary ways, with or without stack frames. This is best shown in the benchmarks: the zerrors there ( v0.2.0 also includes support for modifying the default encoding of zerrors, i.e. if you are migrating from say (*): |
This has been released as a third party package (thanks!). Let's see how that goes before considering adopting this into the standard library in some future release. For now, this is a likely decline. Leaving open for four weeks for final comments. |
@ianlancetaylor I will be trying to spread awareness. Any visibility boost would be very welcome, I not active nor experienced in sharing to the community. |
No change in consensus. |
go2 proprosal: universal WrapError type
See filled questionare #36994 (comment)
This is a go2 proposal in the context of error wrapping. It is a concrete follow up to the more open ended #35929 (errors: how should formatting be handled?).
It requires changes to the errors package but no language change. All code is in this repo.
Context
Error wrapping support was added in go 1.13. It did not introduce some advanced features like error formatting and stack traces, not because these were not desirable (Error Values — Problem Overview, Error Printing — Draft Design) but because no good implementation was found that delivered them. This puts forward an implementation that delivers on the above, and which can easily introduce new feautures going forward.
Abstract
Currently, to be a wrapping error means implementing
interface {Unwrap() error}
.Under this proposal, it means beaing an instance of the new
WrapError
struct, which itself contains plain, non-wrapping errors. The key advantage is new features can be added accross all wrapped error uses by adding functionality toWrapError
, as opposed to introducing additional interfaces that have to be inplemented by every individual error type.Details
Immediate Changes
The following are to be added to errors package (implementations in werrors.go):
type WrapError struct
: effectively a linked list of errors, this is set to become the universal type for all wrapped errors. It supportsIs
,As
andUnwrap
as expected.func Wrap(error, error) error
: used to produce theWrapError
error chain. All error wrapping is set to be produced through this method.This is the extent of the 'immediate' changes put forward by this proposal.
Follow ups
The more advanced features can be built on top of these changes as demonstrated in the following orthogonal extensions. This are in place to demostrate the ease with which such features can be delivered, but are not complete implementations of such features.
Note that the above can be introduced without requiring changes on any other error type other than
WrapError
. More generally, in aWrapError
compliant world adding functionality to all wrapped errors requires updatingWrapError
only.Limitations and Breaking Changes
Note the migration to
WrapError
is needed before the follow ups above (and theremore, the primary gains) can be delivered, butWrapError
andWrap
can be introduced (with no additional functionality) without any breaking change. This allows for a gradual migration before the ultimate breaking changes.The primary backwards-incompatible changes are:
interface {Unwrap() error}
:it was added with go1.13 to the errors package as the fundamental method that defines wrapped errors. Errors implementing this need to be changed to no longer have this method nor contain other errors in their fields, and the wrapping be provided by the new
Wrap
method. This represents the largest breaking change in the proposal. A significant error in this category is os.PathError.fmt.Errorf
support:While
%w
-suffixed strings can be supported, having it elsewhere can't. This makesfmt.Errorf("foo, err=%w, bar", err)
unsupportable, butfmt.Errorf("foo, bar, err: %w", err)
is. Even in the suffix scenario, the requiremenet for formatting imposes for a uniform suffix syntax, presumably the": %w"
that was part of an earlier errors draft. A newfmt.WErrorf(error, string, ...interface{})
without%w
may be altogether more suitable. Note that, more than an implementation detail, such standarisation is required if an error is to support formatting.While the preferred error type checking is via
errors.Is
anderrors.As
, type assertions are still used widely. These will not work as expected underWrapError
,since the type of the error is always
WrapError
even if the last wrapped error is of the type being asserted.The text was updated successfully, but these errors were encountered: