Go 2.0 Error Handling Requirements
gist.github.com
gist.github.com
Currently, your best bet of finding where an error was actually generated, if it is returned a few times before finally being logged/returned to an RPC client, is searching for fragments of the error string and hoping that a) the part that you searched for is part of the literal and not dynamically built b) it is unique c) you can guess the call path that led to this error.
Of course, in a perfect world, all error messages would be so descriptive that you could immediately find the issue just by reading the error message, but unfortunately, ideals and ideology rarely create solutions that work well in the real world.
Go generates a stack-trace for panic() or via runtime/debug.PrintStack(); I recommend the latter before log.Fatal().
// ErrLine returns an error formatted to include the line
// number of where it occurred (presumably with a performance penalty)
func ErrLine(err error) error {
if err != nil {
// notice that we're using 1, so it will actually log the where
// the error happened, 0 = this function, we don't want that.
pc, fn, line, _ := runtime.Caller(1)
err = fmt.Errorf("[error] in %s[%s:%d]: %s",
runtime.FuncForPC(pc).Name(), fn, line, err.Error())
}
return err
}Recoverable errors are definitely a thing, but the original error handling proposal forces the handler chain to eventually return, making it impossible to continue function execution [1]:
> If the enclosing function has result parameters, it is a compile-time error if at the point of any check expression none of the handlers in scope is a terminating statement. Note that the default handler ends in a terminating statement.
As suggested in section H of this post, I think `break` or a similar mechanism inside handlers would be very useful.
[1]: https://go.googlesource.com/proposal/+/master/design/go2draf...
Re 'check', more than half of the counter-proposals suggest various ways to select a named handler, which check cannot do.
There are 3 articles under "In support" and 3 articles under "Against". A pretty literal 50/50 split.
Exceptions are great when you don't want to handle errors properly, but when you do want robust error handling I find the "return a value" pattern much better. Notably even C++ is looking into implementing this!
Sure there is, many important language features boil down to forcing users to do the right thing (not necessarily the easy thing).
In highly concurrent languages like Go, there’s not always a meaningful stack to unwind, and you end up having to pass error values around anyway. So I can easily sympathize with the decision to stick with one mechanism for error handling.
this just causes the users to use another language for their projects instead
A language that provides a lot of freedom when it comes to expressiveness without offering much in the way of constraints (to truly convey the purpose of a given piece of code with the least amount of ambiguity possible) will almost definitely turn into utter crap in contact with junior developers, and will often be a source of pain for more experienced ones once the project is nontrivial, whether they realize it or not.
Not to mention working together with more junior people, in which case it will be you doing the hand-holding instead, because the tools don't
It works because Rust has pattern matching and generics as well. Just having a Result type isn't going to help with error handling much, and Go is not getting generics Rust style nor pattern matching any time soon.
Let us be reminded that Go errors as values are purely a convention, nothing in the language mandates their use. On the other hand panic/defer/recover are language constructs.
Option types demand pattern matching and similar techniques for working with those types. Otherwise you just have "if (x.isDefined) a else b" blocks of code everywhere.
I like Go mostly the way it is. Its simplicity is genius. Anything added should be considered with great care.
Of course you do, that's the point; to unwind the stack until you reach code that knows how to handle the error.
Cancer, really; is that you Gordon?
Problem is you're not handling errors, you're wasting precious energy shuffling errors to code that knows how to handle it; which is exactly what exceptions could do for you. The end result is the same, except it takes more effort and the code looks like crap.