With Go, although you can pass error codes up the stack if you want, you have to do it explicitly. This forces you to think twice before doing so.
This is a key difference: exception handling subtly encourages ignoring errors and letting outer scopes handle them, while error codes force you to deal with your problems within the immediate scope, and then decide what to do from there explicitly.
Personally, I would be OK with that kind of exception handling. I also enjoy Go's error handling. I think Python's exception handling is abhorrent and it constantly bites me in the ass.
There are obviously still non-trivial differences between checked exceptions and Go's error handling, but they aren't as world shattering as unchecked exceptions.
So essentially, use panic/recover as you would a much nicer version of longjmp.
(I believe) the only thing panic/recover lack compared to a more traditional try/catch is typed catching, but idiomatic usage is much different.
Honestly, I really like it. The typed-catching would be nice but the idiomatic usage of exceptions in languages like Java has always rubbed me the wrong way. Exceptions crossing package/api boundaries just seems wrong to me.
You can use reflection with recover to do it, the upside is that it's a more general mechanism the downside is that you need to manually rethrow exceptions you don't handle.
BUT the bottom line is that the standard library doesn't throw exceptions. What you do in your code is really up to you, if you really think panicking across api boundaries is the right thing to do you can, there is no go police coming after you.
There are good reasons to panic across package boundaries. See my other comment. [1]
Go's error handling model is simpler than exception handling. There are fewer surprises. That's pretty much it.
Edit - Things like regexp.MustCompile aside.
The Go standard library:
grep -nrHIF 'panic(' /opt/go/src/pkg/* | wc -l
632
Note that this is somewhat inflated with a lot of `panic("unreachable")` calls. They are a symptom of the standard Go Compiler requiring a `return` on every code path of a function that returns at least one value. A `panic(...)` relaxes this requirement. In this case, a panic arising would indicate a bug in the package. Which is another good reason to panic across package boundaries :-)Do you know if they intend to fix the need for phoney code paths? It seems odd that a language with nice support for first class functions and closures can't acknowledge when "if ... else ..." has complete flow coverage.
It's a purposeful restriction imposed by the Go compiler, but not by the Go language specification.
And I think the idea is to encourage explicitness, and force cases like these:
if cond {
return ...
} else {
return ...
}
Into a simpler: if cond {
return ...
}
return ...
Reasonable people can disagree over whether this is a Good Thing.
It's been enjoyable learning it, though I'm yet to write any code in anger with Go. I find some of the concepts around concurrency and OO design have really made me think about the way I write in other languages.
One thing I cannot quite make sense of though is the treatment of errors/exceptions. This article says: "Exceptions make it too easy to ignore them rather than handle them, passing the buck up the call stack.."
But the example given seems to me to do exactly that:
if err != nil { return err }
Worse still if you forget to do something with err, or don't handle a specific err !=nil situation, it seems easy for control to flow past the error handling and into code that expects no errors.
Are there small, easily understood open source projects written in Go, that would provide tangible examples of the benefit of this error handling approach?
The learning materials thus far have not really convinced me, maybe code in the wild would.