There is probably a similar proposal out-there, but if there is it hasn't surfaced, so I thought I would throw this out there.
It only requires 2 simple changes and is completely backwards compatible.
Currently, idiomatic Go error handling code looks like this:
v,err := somefunc()
if err!=nil {
// do something, in many cases, just return err
}
but a substantial amount of Go code has handling code like this:
v,err := somefunc()
if err!=nil {
goto some_error_handler
}
especially when there is common wrapping of errors, or retries.
With the proposal
https://github.com/golang/go/issues/27165 accepted (at least Rob likes it), the error handling can be simplified by
v,:some_error_handler := somefunc()
which is essentially an if with goto macro.
The only other addition is a compiler provided 'function scoped' variable __error which is the last error returned by the last called function. This allows for trivial writing of the error handler block, as an example:
some_error_handler:
return errors.New("function failed",__error)
or even
some_error_handler:
retry++
if !__error.Permanent() && retry < N {
goto try_again
}
return errors.New("function failed",__error)
And since goto/labels in Go are already scoped, it allows inner handlers, as in:
for _,x := range blah {
v,:localerr := somefunc()
defer v.Close()
x,:localerr := anotherfunc(x)
continue
localerr:
return errors.New("unable to process item ...",__error)
}
I think this coupled with the xerrors enhancements would dramatically improve Go error handling. It is still very explicit, no hidden flow, plays nicely with defer, all returns are explicit, easy to read - no magic.
And if the function has minimal (or no) error handling required, it is written just as before.
A simple enhancement might be a pseudo handler label :return that always returns the 0 values for all results parameters, and __error as the err parameter. In many ways this would be similar to the current 'try' proposal.
The limitation of this solution is that nested calls are not possible as with 'try', but they would instead be done on multiple lines, as in:
v,:return = somefunc()
x,:return = another(v)
y,:return = yetanother(x)
which I think is easier to reason about.
Anyway, just a thought.