3 ms·
I would love to see some in-depth discussion about this. Even in 2022, I don't think it's clear what we want error handling to look like. You can ask for correc
by klodolph 4y ago
I would love to see some in-depth discussion about this. Even in 2022, I don't think it's clear what we want error handling to look like. You can ask for correctness guarantees from the compiler, but it's easy to ask, it's harder to design a system that actually works.
> The lack of exhaustive switch case statements makes this worse because the compiler doesn't care if you're handling all the expected error types (or unexpected ones).
I would love to see how this is supposed to work.
My first thought here is checked exceptions in Java. With checked exceptions, you have a specific set of exceptions that a function is supposed to generate, and a compile-time error if those exceptions are not either handled or propagated. This turned out to be a bit of a disaster in actual practice, and I'm not sure what the fix would look like here.
I'm generally a bit miserable when I try to deal with error handling in Rust, believe it or not.
As for the err != nil boilerplate, I've seen some proposals but I haven't seen anything that was clearly a good proposal. The generics proposal was clearly good, IMO, just for a point of reference.
- gregwebs 4y agoIn Rust you can use the anyhow library if you want a similar level of overhead to Go and similarly aren’t worried about differentiating error cases. What do you think of adopting Zig’s error handling approaches to Go?
- klodolph 4y ago> [...] and similarly aren’t worried about differentiating error cases. I differentiate error cases in Go, so I'm not sure what you're talking about. Sometimes it's done with ==, other times it's done with type assertions, type switches, and some helper functions in the errors package. I've barely touched Zig. I think it's contributing some important ideas, and maybe those ideas will get further developed in newer languages.
- indemnity 4y ago> I'm generally a bit miserable when I try to deal with error handling in Rust, believe it or not. Likewise. I'm a big Rust user, use it for all my personal projects, but error handling is totally unsolved there. - Friction around mapping between error types if I need to "add context and rethrow" - Often lack of stack/trace information for custom error types. Something went wrong the the DB query? Great! Where? Which line of code? There are solutions for these, I try them, and I'm sure someone will pipe up mentioning them (e.g. anyhow, thiserror, miette, etc), but its just so much damn ceremony to do it properly at a particular call site, especially when you are mixing your own code with library code and each library's unique snowflake error types, that I don't do it consistently.
- treis 4y agoI'd like stuff like myFunc() works as today myFunc()^ returns the err if there is one myFunc()! panics if there is an err
- klodolph 4y agoI don't think any option should panic on error. I've had to deal with programs that panic on error and the way I dealt with it was by forking the project and removing every call to panic(). It's even worse with libraries. The other problem is that it's super common to want to wrap the error somehow when returning it. Often you want to wrap the error differently depending on where the error came from in the function, like this: d, err := os.ReadFile(fname) if err != nil { return err // unwrapped } x, err := parseX(d) if err != nil { return fmt.Errorf("%s: %w", fname) } I know that not all Go developers write good error handling code. However, I don't want to make it easier to write bad error handling code if you're not making it correspondingly easier to write good error handling code.
- metaltyphoon 4y agoUnless you put the function name somewhere in the error, there is no way to know where something happened. "Some thing didn't write properly? Cool! Where and which line?"
- dannymi 4y agoIf it's an internal (unexpected) error, panic. You get a backtrace and everything--which helps because it was an unexpected internal error, so you probably messed up. You'd like to know where that is. But if it's an actual user-visible error code then that means you expected for this error to happen eventually and you designed for it. Why then do you need a backtrace? You program is doing what it's supposed to. I mean sure while developing it's nice to be able to just replace the error code emission by panic (which I do sometimes)--but in regular operation? It doesn't help the user at all.
- klodolph 4y ago> "Some thing didn't write properly? Cool! Where and which line?" My eyes glaze over when I'm trying to read stack traces in Java or Python, and then it turns out I can't figure out what's wrong because the stack trace doesn't include the path of the file that failed to parse. What we care about is stuff like: - Program tried to parse file X, - Failed because file X doesn't exist, or because file contains syntax errors, or something - Some context giving us the reason why program tried to read file X, which is usually at a fairly high level (something like "could not load config"). Putting the function name in the error-handling code is something that you SOMETIMES do, but only when it adds important context. If you do it all the time you end up with something completely unreadable, like a stack trace. There are various libraries you can use that give you stack traces for errors in Go, if that's what you want. If I get an error that X is not a valid JSON file--often, that's all I need to know, because I can open X and see the syntax error and fix it. Knowing the name of the function that detected the syntax error is unhelpful, usually, and we have logging + debuggers to help with those cases.
- thiht 4y ago> I've seen some proposals but I haven't seen anything that was clearly a good proposal I have one! Allowing inline ifs, like this: err := func() if err != nil { return err } 1 line instead of 3 for simple error handling, yeaah