4 ms·
> And there is no way to add instance specific information to errors in a later version of a package, because that would require using an error type instead of
by rakoo 10y ago
> And there is no way to add instance specific information to errors in a later version of a package, because that would require using an error type instead of (or in addition to) the existing well known error value, which breaks callers.
Yes you can. Errors are interfaces, not values. As long as you define an Errror() method your struct behaves as an error, but it can have anything a struct has, such as specific information.
You should read Dave's previous presentation (http://dave.cheney.net/paste/gocon-spring-2016.pdf http://dave.cheney.net/paste/gocon-spring-2016.pdf) to understand a bit more about what's already possible today and why Dave's package makes it easier.
- fauigerzigerk 10y agoInterfaces don't help in this case. Say you have a package called net: var Error = ... func Get(url string) (result, error) { if ... { return Error } } Users of your package would do something like this r, err := net.Get("http://example.com") if err == net.Error { //handle this particular error } What if you decide that there are in fact different types errors or you want to return an error code with each error? How would you do that?
- rakoo 10y agoYou should read Dave's presentation again. Asserting for a type is the wrong way to do it, your library should instead provide a helper for the specific parsing you want to do. So if you want to know if this error is temporary, you should have this, inside the net package: func IsTemporary(err error) bool { // specific parsing } Similarly, if you really want an error code: func ErrorCode(err error) int { // a type assertion, which is fine because we're inside the net package v, ok := err.(ErrorWithStatusCode) if ok { return v.ErrorCode } } (Note that in the standard net/http package, the result of an http call is inside the result, never in the error that is returned, whatever the status of the http call is) Basically your package should give all tools so that callers can take a decision without knowing about internals of the package. Knowing the exact error code is probably not what a caller wants; what they probably want to know is whether the error is temporary or fatal, if they can retry with a chance of success, if they can take counter-measures and if they can't alert the user.
- fauigerzigerk 10y agoI think I have read everything Dave Cheney has ever written about errors. But you misunderstand what I'm saying. The standard library is already littered with error values defined on the package level. Many third party packages emulate that approach. Once you have done that in package, there is no way to change it. You cannot add function call specific data to an error after the fact. There is no way to implement an IsTemporary(error) function once you have clients that compare any returned error to a package level singleton using ==. >Knowing the exact error code is probably not what a caller wants I had that need many times. For instance, I needed to get the SQLSTATE from database errors. There is a huge number of SQLSTATE codes and interpreting/classifying them can't be the job of a data access package or even a DBMS specific driver library. Also, how would a networking package know what I consider temporary? Some protocols like HTTP specify some errors to be temporary, but that may not coincide with what I'm willing to retry or not retry.
- zalmoxes 10y agoWhat you're describing with net.Error is a sentinel error. var Error = errors.New("your error string") You can also create a type or a struct that implements error. Example from stdlib: ``` // PathError records an error and the operation and file path that caused it. type PathError struct { Op string Path string Err error } func (e *PathError) Error() string { return e.Op + " " + e.Path + ": " + e.Err.Error() } ``` Dave Cheney's other blog post/talk goes into various ways to handle errors in Go here: http://dave.cheney.net/2016/04/27/dont-just-check-errors-handle-them-gracefully http://dave.cheney.net/2016/04/27/dont-just-check-errors-han...
- fauigerzigerk 10y agoI know all the options I have and I have read everything Dave Cheney (and Rob Pike) has written on the subject. But to quote myself: "there is no way to add instance specific information to errors in a later version of a package". Once you have decided to use a package level error value (sentinel error as you say), there is no way to change that. As there is a huge number of such error values in the standard library and also a substantial number of other types of errors like PathError, "there is no general and reliable way to handle specific types of errors".
- uluyol 10y agoMethods can always be added. Yes the values and types can't be changed but we can extend the existing types to have these methods and give naked error values (errors.New) new types. It wouldn't be breaking the Go1 guarantee because they would still have the type error, only the underlying type would change.
- fauigerzigerk 10y agoAll true, I never said anything different. But what's the point of adding methods? What you can't do is add call specific information to errors returned from a particular function if that function returned a package level singleton value before.
- deleted 10y ago[deleted]
- andrewstuart2 10y agoFurthermore, once you redefine the concrete type, if your callers are expecting some set of well-known error values and checking values, say with equality, then just redefine those variables as instances of the new type. API compatibility maintained.
- HeyImAlex 10y agoYou're usually creating typed errors so that you can attach more structured information, so equality won't work anymore.
- fauigerzigerk 10y agoI don't see the point of doing that. The point is, you can't add data specific to one particular function call to a singleton error value that you define on the package level.