Multithreaded environments make exception handling next to impossible to do correctly. The stack trace only shows a single thread which is often useless without more context. Exceptions are per-thread, so handling has to be per-thread.
Exceptions make the control flow of your program completely obscure. Any line that calls out to another function can cause this function to exit. If you're not wrapping every function call in a try/finally, you're probably doing it wrong (at which point it's even more verbose than go's error returns).
Errors in Go aren't special. They're just values returned from a function. You have the whole language at your disposal to deal with them.
I can write this in Go, and it's perfectly safe:
f, err := os.Open(filename)
if err != nil {
return fmt.Errorf("Failed to open config file: %s", err)
}
err = callFunctionThatMightErrorOut()
if err != nil {
// handle err
}
f.Close()
I know that my code will ALWAYS close that file handle. To do the same thing in a language with exceptions, you'd have to do something like this: File f
try {
try {
f = os.Open(filename)
}
catch(Exception e) {
throw new Exception(string.Format("Failed to open config file: %s", e.Message))
}
try {
callFunctionThatMightErrorOut()
}
catch(Exception e) {
// handle error
}
}
finally {
if f != nil {
f.Close()
}
}
Now who's verbose?The reason people think Go exception handling is verbose is because they aren't really handling errors in their own code. Go makes it easy to handle errors in the right way.