4 ms·
The following illustrates how you use Go errors as if they were exceptions: func A() error { err := compute.Something() if err != nil {
by JulianMorrison 14y ago
The following illustrates how you use Go errors as if they were exceptions:
func A() error {
err := compute.Something()
if err != nil {
return err
}
return nil
}
Throwing errors up the return chain using error values is really very little different than throwing up the return chain using exceptions, except that now there is only one way to return, and it is always clearly marked. You return where you say "return". And you return what you said you would.
- smosher 14y agoWhat am I missing here? This appears to be fully in-band and contains a redundant code path (constituting a NaN bug in languages with incomparable NaN—no idea if that applies to Go) for no apparent reason.
- JulianMorrison 14y agoWhat you're missing is that I'm showing how error throwing and error returning are functionally the same, when you have a standard error type, multiple valued return, and an idiom of returning errors you chose not to handle.
- smosher 14y agoSure, you can handle errors and you can explicitly pass the buck. That's no different than what we do in C. Exceptions are out-of-band (from a regular return value), and what you're talking about is entirely in-band. What you're doing, functionally, is returning a tuple. This is as old as the sun and nothing at all like exceptions. I'm not sure what you think idiom means (Hello, my name is Inigo Montoya), but you never need one to do anything in code. In human language they capture some context and their meaning must be understood by rote or in terms of that context, but in code they are entirely explicit and work just as well before and after becoming idiomatic—which is solely a form of classification that people use and computers don't.
- JulianMorrison 14y agoIdiom just means "a standard way to do things, that everyone recognizes and uses". Normal exceptions, the kind that unroll the stack (and not deep magic like call/cc) are only "out of band" as an optimization. There is no behavioral difference between "save the last place you decided to handle errors, and jump there directly unrolling the stack at once" versus "unroll the stack by a series of buck-passing in band error returns, until you get to the last place you decided to handle errors". A compiler could implement exceptions by silently transforming them into Go form. And a Go compiler could silently transform buck-passing into traditional exceptions.
- smosher 14y agoIn particular idiom does not mean something deliberately entered into the language to solve a particular problem—that's just regular semantics. Idioms are by nature emergent. For example I might be conscious of 3 idioms among all the languages I know (which is much more than 3), yet I write idiomatic code because I know the languages well. In fact, outside of Go circles no one talks of idioms, they talk of idiomatic code. Who cares about compiler transformations? The issue is the semantic difference between return codes and exceptions. Nobody is asking for exceptions because they can't or don't know how to get to the correct scope to handle their errors, they're asking for them because they don't want to write all the boilerplate necessary to do so. And yes, you can transform exceptions to chained returns. That would be a lot of work for terrible performance. You can't do the other transformation though. It would require being able to statically analyze the code path to determine where the errors are eventually handled, which is impossible in the general case.
- azth 14y agoHow is that different from func A() error { return compute.Something() }
- zmj 14y agoThe example is easier to extend to include additional logic after the call or another return value.
- JulianMorrison 14y agoMy point is that whether it's "A() error" or "A() (int, error)", whether it calls one function or three, what it's doing with the error is throwing it up the line, rather than handling it locally. Exactly as if it had said "throw err". So yeah, your version is what I'd shorten it to in practise, it just wasn't quite so illustrative.
- dkersten 14y agoIts not really the same though. The two differences I can think of offhand are that 1) you have to manually pass error up the call stack until you want to handle it, while exceptions are automatically propagated, meaning that you don't have to remember to do this until the point where you actually want to handle the error and 2) exceptions usually contain a stack trace to where they were raised while this method won't (without additional work anyway), so contextual information is lost.