3 ms·
> A popular criticism of Go's approach is that the compiler doesn't force you to handle your errors, which is true, but I find that Go's culture suffices here..
by ansible 8y ago
> A popular criticism of Go's approach is that the compiler doesn't force you to handle your errors, which is true, but I find that Go's culture suffices here...
The Go culture does suffice, but the Rust culture is even stronger here. Everyone is expected to use Result for something that can fail, which I like a lot for consistency's sake.
> The other popular criticism of Go's error handling is that it's verbose, which I wholly disagree with--the verbosity is such a negligible cost that I would much prefer verbose error handling to the language complexity required to elide them (especially if the proposed sugar required baking "errors" into the language as opposed to treating them like any other data).
Six months ago I would have agreed with you. And then I learned about error propagation using the question mark operator in Rust:
https://doc.rust-lang.org/book/second-edition/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator https://doc.rust-lang.org/book/second-edition/ch09-02-recove...
Arguments can be made about creating custom error messages at each call level, but is that really necessary most of the time?
- weberc2 8y ago> Six months ago I would have agreed with you. And then I learned about error propagation using the question mark operator in Rust: https://doc.rust-lang.org/book/second-edition/ch09-02-recove.. https://doc.rust-lang.org/book/second-edition/ch09-02-recove.... Arguments can be made about creating custom error messages at each call level, but is that really necessary most of the time? No, this is not necessary most of the time, and I don't consider the "custom error messages" argument to be a very good argument against sugar. The convincing argument in my mind is that unlike Rust, Go has no trait system to facilitate this sugar, so the alternative is to special-case the compiler to support the error type. Of course, Go could implement a trait system, but "error handling sugar" is a negligible factor in whether or not such a system should exist and how it should be designed. TL;DR--what makes sense for Rust may not make sense for Go.
- jerf 8y ago"The convincing argument in my mind is that unlike Rust, Go has no trait system to facilitate this sugar, so the alternative is to special-case the compiler to support the error type." What do you need out of "traits" that "interfaces" don't provide, for error handling?
- weberc2 8y agoThere isn't infrastructure in the Go compiler for mapping a given sugar to a particular interface. The point isn't traits vs interfaces, but rather that the infrastructure exists in Rust and it doesn't exist in Go (and adding it to Go solely to alleviate a tiny bit of boilerplate is a bad idea).
- jerf 8y ago"And then I learned about error propagation using the question mark operator in Rust:... Arguments can be made about creating custom error messages at each call level, but is that really necessary most of the time?" Actually, one of the things that has prevented Go from "simply" or "just" solving the error propagation problem is precisely the recognition that in real code, if err != nil { return err } becomes problematic at scale, because it obscures the history of the error. Stack traces are great for humans, but not terribly useful for programmatic interpretation. Personally, I still tend to use "if err != nil { return err }" as my sort of default sketch implementation, but I find it is very common for many of those to grow something else before the program ships, and I'm still not all that great or consistent about layering errors properly anyhow. I'd suggest to a lot of people that it may be worth reading or re-reading the Go 2 error proposal [1], and to try to come at it with some relatively fresh eyes, rather than reading it for "does this precisely conform to my preconceived notions about what error handling should be?" (Another interesting aspect is around providing some base API for errors, and processing composite errors, rather than expecting end-users to do all the definition [2]. Personally I consider both important.) There is some legitimately interesting discussion and work around what to do, based on waiting to gather a lot of data about error handling before just slamming a solution into place, moreso than may meet the eye. I can't speak to Rust's solution in practice, but having used Haskell for a long time with union types for errors, I can say they are hardly error-handling nirvana there. If I'm reading the Rust documentation correctly, they're going to have the same problems in Rust as they do in Haskell. [1]: https://go.googlesource.com/proposal/+/master/design/go2draft-error-handling-overview.md https://go.googlesource.com/proposal/+/master/design/go2draf... [2]: https://go.googlesource.com/proposal/+/master/design/go2draft-error-values-overview.md https://go.googlesource.com/proposal/+/master/design/go2draf...
- erik_seaberg 8y agoif err != nil { return nil, errors.Wrap(err, "bad stuff during foo") } looks pretty handy, I just want to tell the compiler to infer that everywhere by default, because writing it over and over is not only a waste of time but actively makes all code harder to read.
- 8y ago