4 ms·
It's easy to criticise this from a visual glance but you have to remember that proper error handling in any language is hard work and often produces ugly code w
by laumars 9y ago
It's easy to criticise this from a visual glance but you have to remember that proper error handling in any language is hard work and often produces ugly code where you need to account for multiple edge cases - many of which aren't serious enough to cause an exception but would still break the program's logic. All Go does is group these conditions into a standard interface.
Furthermore, because Go does unify these conditions, I've found it effective for handling a whole array of differing edge cases that I might have otherwise overlooked. In that regard I've anecdotally found it more effective than most of the habits you see in other languages (I can't say all languages because I haven't used every language out there, but I have developed in excess of a dozen different programming languages over the last 30 years).
In short, in Go error handling becomes a first class citizen rather than a byproduct you begrudgingly need to check for.
Also while it might not be to everyone's tastes, adding "if err != nil {" really does add practically nothing to your overall dev time in real terms.
But I'm not here to advocate one method of error handling over another, nor to try and convince anyone to use Go who might not have otherwise. Obviously you can see I get a little frustrated when people judge it purely on face value but that's because I have spent some time with the language and found it to be surprisingly effective at delivering a stable product.
- amelius 9y ago> Also while it might not be to everyone's tastes, adding "if err != nil {" really does add practically nothing to your overall dev time in real terms. But how do you compose functions then. You can't write: f(g(h(...))) > when people judge it purely on face value Yes, I can see that is frustrating. But I already know the style of programming that requires if-statements instead of exceptions, as I have been programming in C a lot, and I don't want to go back to that style because I'm lazy and I'm sure I will forget to handle some errors. I want my language to deal with this. Honestly, is that really too much to ask? Even javascript has exceptions.
- dullgiulio 9y ago> because I'm lazy and I'm sure I will forget to handle some errors I really think you should try Go before being so convinced about your assertions. It's not easy to forget error handling in Go. And letting exceptions bubble up all the way will improve things how?
- masklinn 9y ago> It's not easy to forget error handling in Go. It's very easy to do so if the function has no useful return value or you don't care for it e.g. Writer.Write: https://play.golang.org/p/cPh0PJoz-v https://play.golang.org/p/cPh0PJoz-v > And letting exceptions bubble up all the way will improve things how? Errors the developer forgets (or does not want) to handle will trigger a default handler.
- garfij 9y agoIn practice, what you end up doing is adding the `errcheck` linter to your build process and it finds all instances of you not dealing with an error return and it's "just-as-good" as a compile time check.
- erik_seaberg 9y agoA stack of ten functions doesn't need to explicitly catch and re-raise the exception ten times to get it to where it can be handled.
- NateDad 9y agoSure, and then you have no idea what was executed and what failed. Did you run 9 functions or 1? What do you need to roll back? How do you handle the error? This is the problem with exceptions. They make it too easy to be lazy with your error handling.... Most of the time it's just catch and log, because the code itself has no way of knowing what failed and what succeeded. This is how you get your program in a bad state.... Because maybe you uploaded the file but didn't set the metadata in the API, because the connection broke between those steps. With go's error handling it forces you to think about "what happens if the code fails here". Its always obvious what code had been executed and what has not. To get that behavior in exception oriented languages, you'd have to wrap every call in try/catch, which ends up just as verbose as go, if not worse.
- masklinn 9y ago> Sure, and then you have no idea what was executed and what failed. Did you run 9 functions or 1? What do you need to roll back? How do you handle the error? > […] > With go's error handling it forces you to think about "what happens if the code fails here". Did it run 9 functions or just 1? What do you need to roll back? How do you handle the error? The inner code could have just bubbled an error by hand from a deeper call (or the library could even have used panic/recover internally to do so, the stdlib used to do that). You have no more idea than in the exceptions-based code unless you have the source available right there, which you'd then also have in an exceptions-based language. > To get that behavior in exception oriented languages, you'd have to wrap every call in try/catch, which ends up just as verbose as go, if not worse. So your argument in support of Go's error handling is that the very worst case of exceptions-based error handling you can imagine is about as bad as the baseline case of Go's?
- laumars 9y ago> I don't want to go back to that style because I'm lazy and I'm sure I will forget to handle some errors. Because errors are a returned interface you don't forget to handle them. In fact you have to explicitly tell the language not to handle them by using a _ token on the function call. However it sounds like your argument is more personal preference regarding coding style (eg it seems you tend to favour Sexpression style of syntax over the C-style of syntax) and that's reasonable enough. I do write a lot of code like that too - albeit not in Go.
- konart 9y ago>But how do you compose functions then. You can't write Not all functions have to return an error. You can come across something like func(x, y, func() { ... }) Pretty often. Anyway, I'm not quite sure how is that different from, say, Ruby's begin...rescue.
- masklinn 9y ago> Anyway, I'm not quite sure how is that different from, say, Ruby's begin...rescue. Ruby lets you write foo(bar(baz())), the rescue block will just coalesce errors in any of the three calls. And because Go has no generics and its errors are not reified (handled through MRV which is a special language construct) you can't build abstractions like flatmap/then/>>= which would let you compose these functions (or function calls), you have to handroll every instance.
- erik_seaberg 9y agoAs a special case, Go does allow foo(bar()) if foo takes two args. What it doesn't allow is foo(bar(), baz()) with errors.
- masklinn 9y ago> As a special case, Go does allow foo(bar()) if foo takes two args Good to know (though somewhat disgusting), but for error-returning functions I would assume the external ones would take a single argument aka in foo(bar(baz()) I'd expect func foo(arg W) (result X, err error) func bar(arg V) (result W, err error) func baz() (result V, err error)