3 ms·
People are overly dramatic when it comes to typing err != nil. I’m not going to say it’s a holy grail in error checking. But I have yet to be convinced on the b
by fsociety 3y ago
People are overly dramatic when it comes to typing err != nil. I’m not going to say it’s a holy grail in error checking. But I have yet to be convinced on the benefit of exceptions vs. the hell hole of complexity they bring.
They stuck to their guns, took what C did, and made it 1000x better. And in the same sweep made a language that is dead simple to read and code review.
- lamontcg 3y agoThe alternative isn't exceptions. Neither this idea or rust's '?' operator are exceptions.
- josephcsible 3y agoIt's not that it's hard to type. It's that in Go, if you make a mistake with your error checking, your program has a bug. In better languages like Rust and Haskell, if you make the same kind of mistake with error checking, your program doesn't compile. And Go isn't even close to 1000x better than C. It makes almost all of the same mistakes that C did (especially the billion dollar mistake), despite being new enough that it should have learned from them.
- danenania 3y agoI like both Haskell and Rust (in theory; haven't written anything nontrivial in either). But they both seem to encourage you to spend a lot of time and energy on the meta aspects of programming. You can build safe, beautiful systems, but you can also happily spend all day (all week? all month?) playing various forms of code golf without actually producing anything. Go, like C, is a very get-it-done language. It doesn't let you have any fun at all with abstractions, so you end up just doing your work instead. In spite of its warts, I think Go is remarkable and unique for this quality.
- HippoBaro 3y agoThere's absolutely nothing in Rust that mandate error handling. You can always ignore them, just like in any other language.
- josephcsible 3y agoRust's type system mandates it. If you disagree, then post a Rust program that uses the result of a call to std::fs::read_to_string without specifying how to handle an error.
- rollcat 3y agoIt's about how hard it is to make a mistake in well-intentioned code. The number of times my fingers typed "if err != nil" when what I did actually mean was "if err == nil" is too damn high, and the consequences often dire. I usually prefer Go to Rust (and even defend Go's error handling most of the time), but that's the one aspect that Rust handles 1000x better: the common case must be easier, so that you don't get as easily tripped up by the uncommon.
- 015a 3y agoI mostly agree. People read code like this and think: its verbose and repetitive. if err != nil { return nil, err } But, I almost never write code like that. What I'm usually writing is some formulation of: if err != nil { return nil, fmt.Errorf("Error fetching thing: %v" err) } Sometimes; you wrap to add additional context. Sometimes; you wrap to get a generic error type into a package-specific error type. Sometimes; you wrap to get, idk, some kind of project-wide HTTP-oriented error type. Error wrapping is the pattern in Go; which is very different from exception-oriented languages. I like this article's syntax for a straightforward "throw error" situation. I wouldn't support its addition, but I wouldn't oppose it either. However, I struggle to imagine a more concise Go-ish syntax I like which supports a "wrap and throw" type situation. Maybe something like: v1 := Thing1()! v2 := Thing2() ! fmt.Errorf("Error fetching thing: %v" err) Phrased in english; the bang operator can follow any statement that resolves to a multi-value function return where the last value is an error type, and the statement is in a function body whose last return value is an error type. If this function returns a non-nil value as its last value; If nothing follows the bang, it bubbles up this non-nill error with no wrapping. If a statement follows the bang, that statement gains an implicit `err` value containing the error value the LHS statement resolved to; and it can return a new error-type which then gets bubbled up. But, again; I don't love or even really like this, its just the best I can come up with. Its not that much shorter than writing it out. Its not obvious how it should behave in the presence of an outer-scoped variable named `err`. Its not obvious how the bubble up should handle the other non-error return values (zero value I guess?) One thing I rather like about Go is; if you're catching and re-throwing wrapped errors, which is a pattern I like, its actually far more concise than exception oriented languages. The same thing in JS? let v; try { v = Thing() } catch (err) { throw new Error(`I died: ${err}`); } So; you rarely do that. But in Go, its barely harder to wrap and re-throw than it is to just directly throw; so people do it more often.
- thiht 3y agoTo be fair, you wouldn't do that in JS because exceptions have a stack trace, so you don't need to add the context on every return. The downside is that since you don't "need" to catch your exceptions, you don't think about them. That's one thing I really like with Go, errors are in my face all the time, so I have to think about them. Even if I write the infamous if err != nil { return err } at least I do it consciously. And when I or my colleagues read it 2 months later, we know from reading that this can return an error, and we see clearly how it was handled, so we can think about it and visually see if it was handled correctly. Reviewing and reading code with exceptions is a nightmare, because you have no idea if errors were handled correctly. On every call you have to guess if it throws or not.
- pjmlp 3y agoWhere Go is definitly better than C is being safe by default, with automatic memory management and proper modules, that is it. So yeah, an alternative for those that be writing C otherwise, and at least Go helps making the world safer even if with a draconian language design.
- HippoBaro 3y agoThis! These fancy operators add a lot of complexity in practice. Trivial things in Go like error wrapping (to add local context), become much more complicated with `?` operators. Go made something super simple. I write and review a lot of Go code daily, and I don't quite get how these error branches are such a big issue. The code is always very simple to follow through.
- closeparen 3y agoI propose a simple split. When you are writing a daemon or background job whose goal is to never ever stop, then exceptions are indeed a minefield of complexity. When you are writing a collection of HTTP/RPC handlers, exceptions semantics are almost always correct: whatever goes wrong just needs to bubble up the stack and become a 5XX for the caller. Being able to “handle” without propagating needs to be possible but is rare enough that it should be opt in.