6 ms·
Try makes it worse because it is so easy to miss when reading the code. Because it encourages nesting function calls, which is harder for a human to parse than
by NateDad 7y ago
Try makes it worse because it is so easy to miss when reading the code.
Because it encourages nesting function calls, which is harder for a human to parse than separate statements across lines.
Because it means you can exit the current function from the middle of a line of code, and what runs before or doesn't run before is based on order of operations rather than requiring the exit to be a statement on its own line whose order cannot be misunderstood.
Because it discourages giving more information with an error, so instead of "failed to open config file: EOF", you just get the EOF.
Go's error handling isn't any more error prone that writing if statements for all the rest of your code. if err != nil is no different than if age < 18. Either one is a branch in the code. I can literally count on one hand the number of times in 6 years of full time go development that I've seen people miss writing the if err != nil.
Being explicit is good. Spreading out the logic is good. Cramming a lot of logic into one line is bad.... and that's the sole purpose of try.
Maybe there's another way to make error handling better in Go. I'm not averse to looking into that. But try wasn't it.
You're talking about writing if err != nil being tedious, but what about matching Results from Rust, isn't that tedious? What about writing proper catch blocks in java or C++ or python, isn't that tedious? It's all just logic.
- wybiral 7y ago> Because it encourages nesting function calls, which is harder for a human to parse than separate statements across lines. I absolutely agree. Beyond the human parsing aspect it also makes commit changes easier to reason about and review. I want functionality to be limited per-line and view the ability to combine a lot of functionality into one line as a liability more than a benefit. Go's error handling isn't carefree or hands-off, but that's because error handling is serious. Especially in network code and cryptography.
- gigatexal 7y agoI thought it could lead to doing method chaining for a fluent like API which I find cleaner than how things work now.
- saturn_vk 7y agoThat can easily be done right now with the current way of error handling.
- gigatexal 7y agoDo you have any examples?
- NateDad 7y agoI really dislike method chaining. I'd much rather have 5 lines than 5 chained methods. If that's too much to read, you can always encapsulate it in a well-named function.
- gigatexal 7y agoBut five functions that return a value and an error would each have to run the if err != nil dance whereas with method chaining it's cleaner
- NateDad 7y agonot if each one can fail. What if call #1 and call #3 can return the same error.. how does the caller know which one failed? This is the same as wrapping a bunch of calls with a catch (Exception) ... you lose context of what failed and can't behave differently for different failures. All you can do is perform a generic "something went wrong" behavior.
- mikeschinkel 7y agoInterestingly you _can_ implement method chaining to require a terminal method call i.e. err := GetFoo().SetBar(1).SetBaz(2).Run() and then each chained method would set an error property in the object and if err!=nil then do nothing but return the object, and then the last method could return the error value. That said, I am not a huge fan of fluent interfaces. I much prefer passing in a struct as an "args" parameter, in most case (but not all.)
- tsimionescu 7y agoThe difference with catch blocks in Java, C++ or Python is that you only need to write them when you actually have something g meaningful to do. If you only need to propagate the error or cleanup resources then propagate the error, then all you would write is... Nothing. And cleanup+propagation is by far the most common error handling strategy. In Java and Python exceptions even add context for you automatically to help track down what happened.
- sagichmal 7y agoOne foundational principle of Go is that the sad path is at least as important, and maybe more important, than the happy path. The best Go programmers I know write the sad path of their programs first, and then backfill the happy-path logic. So: > you only need to write [error checking] when you actually have something meaningful to do. Although it's the subject of a lot of ridicule, `if err != nil { return err }` is actually bad Go code, and not often written by good Go programmers. Errors in Go are, at a minimum, annotated with contextual information before being returned. Frequently, they are programmed-with in other, more sophisticated ways, depending on the domain of the program. Shifting your mindset to understand errors as something significantly more important than the off-gassing of your program's execution is worthwhile in general, and, in Go, fundamental.
- VMG 7y ago> Errors in Go are, at a minimum, annotated with contextual information before being returned. What surprised me when I last wrote Go was that there was no out-of-the-box solution to adding a stack trace to the error.
- ithkuil 7y agoyeah; we're getting there though, see https://github.com/golang/go/wiki/ErrorValueFAQ https://github.com/golang/go/wiki/ErrorValueFAQ
- Cthulhu_ 7y agoDoes anyone know if this was a conscious decision? I mean IIRC in Java you're generally discouraged from throwing errors for control flow because creating the stack trace is a relatively heavy process. In Go this is of less concern and returning an error is pretty normal for control flow (as in errors are expected, not exceptional), and you shouldn't have to worry that an error path would be 100x as expensive as a normal flow because a stack trace is being generated.
- akavel 7y agoWriting Go professionally for 4 years already and being a Go fanboy since 2009: while endorsing many benefits of "if err" blocks, I do very much have the following issues with them (in no specific order): - It's hard to spot outliers. This leads to occasional bugs that tend to get easily overlooked in code review. Also, it makes code reading harder when an "if err" block is subtly different. The most common case here being "if err == nil" (sometimes bug, sometimes on purpose) - super hard to notice. - You say you have seen missed "if err" blocks only a few times. I say that's 100% too many; every one of them in my experience was a subtle bug (possibly comparable to off-by-one errors in C). - When I need to focus on understanding/analyzing the optimistic path in a fragment of code (always the first thing I do when reading), the everpresent "if err" blocks introduce tiresome visual noise and make the reading/grokking process slower and harder (having to constantly try and mentally filter out some 80% of what my eyes see).
- mikeschinkel 7y agoJust curious. Do you have a vision for how Go could change to improve your issues? (One of the key problems is nobody could agree on a better approach...) Also, what editor/IDE do you use? The reason I ask is because of this: https://youtrack.jetbrains.com/issue/GO-7747 https://youtrack.jetbrains.com/issue/GO-7747