https://github.com/golang/go/issues/32437
https://github.com/golang/go/issues/32437#issuecomment-51203...
https://github.com/golang/go/issues/32437
https://github.com/golang/go/issues/32437#issuecomment-51203...
https://golang.org/doc/faq#assertions
> Why does Go not have assertions?
> Go doesn't provide assertions. They are undeniably convenient, but our experience has been that programmers use them as a crutch to avoid thinking about proper error handling and reporting. Proper error handling means that servers continue to operate instead of crashing after a non-fatal error. Proper error reporting means that errors are direct and to the point, saving the programmer from interpreting a large crash trace. Precise errors are particularly important when the programmer seeing the errors is not familiar with the code.
> We understand that this is a point of contention. There are many things in the Go language and libraries that differ from modern practices, simply because we feel it's sometimes worth trying a different approach.
But error handling is just awkward. I do not mean the retval, err := funccall(a,b) syntax but rather the absence of a standardized way to get stack traces.
Fundamentally, the Go team made the correct choice between explicit and implicit error handling. Yet one would hope for a bit terser syntax and language supported stack traces, 11 years after launch.
For a good overview of the issue: https://go.googlesource.com/proposal/+/master/design/go2draf....
The Go team tried, but the community shot it down.
Your link was the first proposal, and this was the second proposal: https://github.com/golang/proposal/blob/master/design/32437-...
Simple cases are already simple. It's the harder spots that need help.
func whatev() (err error) {
defer helper(&err, "mightFail context to help debugging", some, vars)
try(mightFail())
defer helper(&err, "alsoMightFail context to help debugging", some, vars)
try(alsoMightFail())
}
if the second call fails, your error has now been wrapped twice.There are of course ways to deal with this. You can add a "already wrapped" sentinel of some kind (say, a * bool that they check and modify), or use a `helper := once(helperfn)` to do that same kind of thing internally... but that's more verbose. And can't be done generically without reflection (though `func(*error, string, ...interface{})` would be quite common, which might be good enough). Inline handlers shown in many examples are even worse since they can't be composed as easily, so you'd probably end up maintaining a bool var between all handlers. By hand.
They both also require naming your `error` return value, which requires naming all returned values, which has been a depressingly large source of shadowing and not-initialized-value mistakes in my experience. Improperly-initialized values especially, as those tend to cause problems a fair distance from the cause, and sometimes go unnoticed for quite a while.
tl;dr it adds more easily-forgotten boilerplate to non-trivial error handling, and makes it and related code more mistake-prone. I'd rather have `return fmt.Errorf(err, ...)`, it fairly naturally resists growing more complex as your func grows more complex.