This is a very good presentation of the feature, thank you Donald!
I would also add that unfortunately the only way to create a chain seems to be through the use of custom error types that implement the Wrapper interface, while it's not possible to wrap more than one and only one specific error solely with fmt.Errorf().
You show how that is done with custom errors that have the Unwrap method, which is great, but it's important to specify that it's the only method to create chains.
It's also interesting to offer a concrete scenario where we might need chains. You mention deep callstacks, which is true. One other way I use chained errors is to have "markers" of specific events when multiple non-fatal errors can occur in a single call.
Instead of returning explicitly, say, an []error or SomeCustomError, the Golang guidelines recommend to always declare a simple error as return values, which by virtue of being a chain are still able to convey multiple separate events if the caller wants to dig deeper with Is and As.
In practice, for clarity, the following does not appear to be possible at the moment using exclusively fmt.Errorf().
I cannot find any way to create an err3 exclusively with fmt.Errorf() such that both of the following statements are true:
errors.Is(err3, err1)
errors.Is(err3, err2)
This is unfortunate to say the least. One would have hoped that when the Go Team introduced errors.Is(), errors.As() and "%w" they would also give the built-in error type the ability to create chains, or that they would provide some utility function to that effect.
Maybe they didn't because of the non-breaking promise, but still it's inconvenient and as a result native error wrapping is vastly underused.
This is a very good presentation of the feature, thank you Donald!
I would also add that unfortunately the only way to create a chain seems to be through the use of custom error types that implement the
Wrapper
interface, while it's not possible to wrap more than one and only one specific error solely withfmt.Errorf()
.You show how that is done with custom errors that have the
Unwrap
method, which is great, but it's important to specify that it's the only method to create chains.It's also interesting to offer a concrete scenario where we might need chains. You mention deep callstacks, which is true. One other way I use chained errors is to have "markers" of specific events when multiple non-fatal errors can occur in a single call.
Instead of returning explicitly, say, an
[]error
orSomeCustomError
, the Golang guidelines recommend to always declare a simpleerror
as return values, which by virtue of being a chain are still able to convey multiple separate events if the caller wants to dig deeper withIs
andAs
.In practice, for clarity, the following does not appear to be possible at the moment using exclusively
fmt.Errorf()
.Given two simple errors:
I cannot find any way to create an
err3
exclusively withfmt.Errorf()
such that both of the following statements are true:This is unfortunate to say the least. One would have hoped that when the Go Team introduced
errors.Is()
,errors.As()
and"%w"
they would also give the built-inerror
type the ability to create chains, or that they would provide some utility function to that effect.Maybe they didn't because of the non-breaking promise, but still it's inconvenient and as a result native error wrapping is vastly underused.
this is so true, man. Is there a way to do this now?