3 ms·
>Idiommatic Go is to have several lines of boilerplate after every single function invocation which can possibly fail. This is an issue in every language. If y
by oofabz 14y ago
>Idiommatic Go is to have several lines of boilerplate after every single function invocation which can possibly fail.
This is an issue in every language. If you want to do something that might fail, you have to handle the possibility of failure. There are only two ways to handle this - return values and exceptions - and they differ in style more than in functionality.
So what is this guy suggesting? Does he want Go to have exceptions? Or does he want every function to magically succeed somehow? I don't enjoy writing error handling either but I see no way around it.
- azth 14y agoSee Scala futures and promises.
- swift 14y ago> There are only two ways to handle this - return values and exceptions - and they differ in style more than in functionality. "There are only two" is a bit strong. Off the top of my head I can think of conditions and restarts in e.g. Common Lisp (to be fair, these are a generalization of exceptions) and monads in e.g. Haskell. I'm sure there are others I'm forgetting.
- jrockway 14y agoI think he wants a non-boilerplate way of doing operation b only if operation a succeeds. Instead of writing: result = operation_a() if not result: return ERROR result = operation_b() if not result: return ERROR return result He wants to write: operation_a() return operation_b() This is a logical thing to want, because the program is not semantically correct if operation b executes after a failed operation a. It is correct, however, if a failing operation_a causes the entire routine to fail by bailing out early. So it would make sense that that be the simplest thing to write, and then make the case where you ignore errors from operation_a be the thing that's a lot of lines of code. Ultimately, it's a problem of not enough abstraction. Users of traditional programming languages are held hostage by the control-flow abstractions that the language designers put in place. But if they weren't, then they'd simply write the top code block and call it "combine_failing_operations" or something and they'd write their program in terms of combine_failing_operations: combine_failing_operations( operation_a, operation_b) Of course, combine_failing_operations is itself a failing operation, so one can also write: combine_failing_operations( combine_failing_operations( operation_a, operation_b), operation_c) The reason why people don't is because the resulting code is ugly and it's not encouraged by the langauge's style guide (which usually says, "I'm the programming language designer, if there's missing functionality it's because the functionality is wrong"). In languages where function application is the only syntax, though, this pattern shows up all the time. For example, in Haskell, you normally combine two functions with the . operator. (f . g) x = f(g(x)). It follows that if you want to combine two functions that can fail, you'll just write that function. Haskell does exactly this and even gives you some syntax sugar: if you call your function >>=, then you can write: do operation_a operation_b instead of "combine_failing_operations operation_a operation_b", which means you get both pretty code and context-specific only-written-once correctness. Semantically this is what Go does, but the syntax isn't as nice. (Exceptions are certainly irritating when applied to Go's concurrency model, but at least they are fail-safe. I don't trust myself to get every line of code 100% correct, and I want my program to crash when it gets into a state I didn't write code to handle. Go makes this harder than it should.)
- oofabz 14y agoThanks, that looks like a good way to handle errors. Go does have a panic() function for your situation. It takes an argument of any type. You can catch it with recover(), or the application crashes. It's like throwing an exception except you can't catch a specific type.