7 ms·
This seems to be exactly the attitude of Go: "We believe that coupling exceptions to a control structure, as in the try-catch-finally idiom, results in convolu
by dchest 15y ago
This seems to be exactly the attitude of Go:
"We believe that coupling exceptions to a control structure, as in the try-catch-finally idiom, results in convoluted code. It also tends to encourage programmers to label too many ordinary errors, such as failing to open a file, as exceptional.
Go takes a different approach. For plain error handling, Go's multi-value returns make it easy to report an error without overloading the return value. A canonical error type, coupled with Go's other features, makes error handling pleasant but quite different from that in other languages.
Go also has a couple of built-in functions to signal and recover from truly exceptional conditions. The recovery mechanism is executed only as part of a function's state being torn down after an error, which is sufficient to handle catastrophe but requires no extra control structures and, when used well, can result in clean error-handling code."
http://golang.org/doc/go_faq.html#exceptions http://golang.org/doc/go_faq.html#exceptions
In Go, if there's a programmer error, call panic(); if there's a non-programmer error, return it as a second return value.
[Added] Plus, it's obvious to see where people ignore errors:
f, _ := os.Open("filename")
"_" is a throw-away variable to indicate that this value won't be used in the code. It's obvious that the programmer decided to ignore the error.
f, err := os.Open("filename")
If you don't use "err" later, this won't compile.
f, err := os.Open("filename")
if err != nil {
// handle error
}
This code handles error.
- PaulHoule 15y agoThis is a bad idea that keeps coming back again and again. I see nothing wrong with exceptions, I do have a problem with (1) checked exceptions, and (2) catching exceptions prematurely and (3) people not learning how to use "finally" so they do (2) and rethrow. Languages like Go and Scala roll out various mechanisms that bring us back to the bad old days of C, when we had to check the return/value and or the error code after every function call... if we wanted error handling to work. The trouble with this approach is that it increases code bulk. For CS class projects, this isn't so bad, but when you're building real systems, the complexity of the error handling can approach or exceed the complexity of the "normal" path and when that happens you're in deep trouble. Exceptions drastically reduce code bulk by introducing default "abort" behavior, which can itself be aborted at any level of the program and which can invoke cleanup anywhere in between. Many programmers in many situations would be perfectly happy to catch "failure to open a file" and "failure to open a database connection" and "failure to connect to a network host" with one simple handler that logs the failure and either aborts, retries or ignores.
- chollida1 15y agoI think the point is that your specific cases: > Many programmers in many situations would be perfectly happy to catch "failure to open a file" and "failure to open a database connection" and "failure to connect to a network host" with one simple handler that logs the failure and either aborts, retries or ignores. aren't exception appropriate a according to a certain portion of developers. The reason they aren't exception appropriate is that you should expect these things to happen from time to time, ie they are not exceptional. using exceptions to handle them is part of the problem Go attempts to solve by having multiple return values.
- Dylan16807 15y agoAs far as I can tell either your point is a circular argument or it's an English-language nomenclature complaint fixable by s/exception/fooglewoo/. Either way it doesn't address the real argument, about where it is appropriate to use try and catch. What is inherently better about multiple return values at every level, compared to semi-centralized catch blocks?
- msbarnett 15y agoIt's not really an objection to terminology. "Fooglewoo" handlers would still exist outside the normal flow of control while handling things that many people would consider routine. Burying that kind of every-day, expected-circumstance logic in a side channel is, at least in some developers opinions, detrimental to the readability and understandability of a program.
- chollida1 15y agoI'm sorry, I can't really parse your argument. My point was that there is a school of htought that exceptions should only be used in "exceptional" circumstances. The examples given were not exceptional in that a programmer should expect those types of errors during the normal execution of their program. Therefor exceptions aren't the solution to those types of errors. Does that make more sense to you?
- sausagefeet 15y agoI don't think this style is much better than exceptions. I think Go could have done itself a favor if it has variants + pattern matching. I find those to be, in many cases, superior to exceptions as the compiler checks you are handling everything and you can easily encode success and failure in the variant type.
- vog 15y agoThis is exactly what I observed when using OCaml: Although it provides exceptions, I almost never used them. Most things were a lot simpler to implement via pattern matching (http://caml.inria.fr/pub/docs/oreilly-book/html/book-ora016.html http://caml.inria.fr/pub/docs/oreilly-book/html/book-ora016....).
- pyre 15y agoThis: > We believe that coupling exceptions to a control > structure, as in the try-catch-finally idiom, > results in convoluted code. Seems at odds with this: f, err := os.Open("filename") if err != nil { // handle error } You're still using a control structure (if-statement) to handle the error.
- kinghajj 15y agoBut that control structure isn't specific to handling errors, unlike try/catch. I think that's what they meant.
- 0xABADC0DA 15y agoFor some context here's another error handler in Google Go: defer func() { if r := recover(); r != nil { if err, ok := r.(runtime.Error); ok { if err.String() == "runtime error: index out of range" { // handle bad index return } } panic(r) } }() vs try { } catch (IndexOutOfBoundsException ex) { // handle bad index } A language where you have to resort to string compare to handle invalid array accesses can't be use as a model for good error handling IMO. Of course that's just the tip of an iceberg with no way for IDEs/tools to know what return is an error, no way to know at a glance if "_" was an ignored error or ignored other extra return value, plus other fundamental problems caused by implicit types.
- enneff 15y agoWhose crazy code is that? NOT idiomatic. If you need to recover from bad slice indexes then your code is broken and you have way more to worry about than a messy recover closure.
- 0xABADC0DA 15y ago> If you need to recover from bad slice indexes then your [error handler] code is broken You bring up a good point that when resorting to value comparisons for error handling instead of type comparisons it's easy to make mistakes. The code is as far as I can tell a simplest way to handle an index out of bounds, but to also handle a 'slice out of bounds' it would need to also compare to the string value "runtime error: slice bounds out of range" -- not helping the case for error handling in Google Go. This code strikingly shows deficiencies in Google Go non-local error handling: - Tons of boilerplate (defer, recover, re-panic, type check, value check) - Not scoped so can only handle an error once per function - Have to do value tests in addition since types are very generic due to implicit interfaces - Error values are poorly defined - Result for higher-level caller is buried deep in the function and non-obvious These problems extend to all non-local error handling in Google Go, not just for this specific case of array and string indexes. That the idiomatic way to 'handle' an error is to abort the program is another separate problem.