Live data from Hacker News

Gopher Wrangling: Effective error handling in Go

stephenn.com

41–50 of 310 posts

Re: Gopher Wrangling: Effective error handling in Go

#41
post #29

Earlier quoted context omitted.

In rust the type system enforces you check the error. In go, it doesn't. (Because rust error types are enums/sums and go error types are structs/products). This seems like a huge difference. > In many cases it's arguably worse because now 1 token is potentially representing two very different types I want to deal with. Yes, that's what an enum/sum type is? That's the whole point.

In rust it is not possible to use incorrectly, and in go it is, sure. But whether it is possible or not is only one dimension. Does it matter that it’s possible to misuse errors in Go if it virtually never happens? I just don’t find the point about what is possible interesting. The other trade offs around readability, ergonomics, and so on seem more impactful.

It depends if you find value in exhaustive pattern matching.

From years of using C's switch statements, I'm not going back.

Re: Gopher Wrangling: Effective error handling in Go

#42

Surprised that the "always wrap your errors" rule isn't in there. It's been the rule in the last few Go teams I've been in.

We moved away from wrapping them recently for performance reasons.

How much of a performance hit were they causing?

Re: Gopher Wrangling: Effective error handling in Go

#43
post #19

Earlier quoted context omitted.

Result is better because it actually encodes the correct situation. You either get a file or an error. Not neither, not both. Go's encodes instead "you may or may not have a file" and "you may or may not have an error". Not the same thing, and extremely rarely what you want, IME. Other languages also do a better job of helping you verify that you actually handled both cases too. By the way I wouldn't say we need Mona…

The Result approach believes that the producer knows what is best for the caller regardless of who the caller is. The Go approach believes that the producer shouldn't assume it knows the caller. I'm not sure one is better than the other, just different tradeoffs.

Doesn't the producer know best whether the producer failed?

Re: Gopher Wrangling: Effective error handling in Go

#45

There is a lot that I like about Go. Error handling is not one of them. On one hand, I appreciate the simplicity of it all. Nothing special about an error, it’s just part of how you do everything else. But on the other hand, there is something clearly special about an error. It’s something 100% of go users have to deal with in almost every single function call. There is something clearly special about it. These grass…

if you write a line of code that can fail, then you should deal with the possibility of that line failing there, directly, in-line _how_ you deal with that failure is a separate question but it's critical that every fallible expression explicitly and visibly demonstrates the possibility of failure this is in no way an "error handling mess" -- on the contrary, it is basically the only way to produce robust and reliabl…

i wish people understood this thinking about and handling all errors, as a prime functiom of the code, is why things like Linux and C Python and X server and git and so on are so reliable.

Re: Gopher Wrangling: Effective error handling in Go

#46
post #29

Earlier quoted context omitted.

In rust the type system enforces you check the error. In go, it doesn't. (Because rust error types are enums/sums and go error types are structs/products). This seems like a huge difference. > In many cases it's arguably worse because now 1 token is potentially representing two very different types I want to deal with. Yes, that's what an enum/sum type is? That's the whole point.

In rust it is not possible to use incorrectly, and in go it is, sure. But whether it is possible or not is only one dimension. Does it matter that it’s possible to misuse errors in Go if it virtually never happens? I just don’t find the point about what is possible interesting. The other trade offs around readability, ergonomics, and so on seem more impactful.

> Does it matter that it’s possible to misuse errors in Go if it virtually never happens? I just don’t find the point about what is possible interesting.

If you knew for sure that it virtually never happened, maybe not. But you don't. At best you know that a few particular individuals you're familiar with never mess it up (but then again, consider the people who "virtually never" write incorrect C). You can't trust random packages you haven't vetted, and you certainly can't trust code written by your junior software engineers.

> The other trade offs around readability, ergonomics, and so on seem more impactful.

Sum types have significantly better ergonomics. `(Result | null, Error | null)` takes four branches to handle properly, whereas `Either Result Error` takes two. And of course things get much worse once you're more than one layer deep, which in a language as procedural as Go you almost always are.

Re: Gopher Wrangling: Effective error handling in Go

#47
post #11

Earlier quoted context omitted.

One thing I don't get (and would honestly appreciate if was explained to me) is how the Result monad differs significantly from Go's error handling, other than being a "true" monad. Most Rust code I see does things like (from the docs): let greeting_file_result = File::open("hello.txt"); let greeting_file = match greeting_file_result { Ok(file) => file, Err(error) => // handle err }; It isn't much different from: fil…

The Rust code you have isn't idiomatic. It's gar more likely to see: let greeting_file = File::open("hello.txt")?l vs file, err := os.Open("hello.txt") if err != nil { return fmt.errorf("faild to open hello; %w, err) } However, I would argue the distinction isn't just cosmetic. The compiler prevents me from not checking the error and blowing up the application with a nil pointer exception. The TFA even capes this pat…

Not a Rust programmer, but I took the Rust code from the Rust book. Admittedly I didn’t read the whole chapter, perhaps they talk idioms later.

Re: Gopher Wrangling: Effective error handling in Go

#48
post #11

Earlier quoted context omitted.

One thing I don't get (and would honestly appreciate if was explained to me) is how the Result monad differs significantly from Go's error handling, other than being a "true" monad. Most Rust code I see does things like (from the docs): let greeting_file_result = File::open("hello.txt"); let greeting_file = match greeting_file_result { Ok(file) => file, Err(error) => // handle err }; It isn't much different from: fil…

The biggest difference is in rust you have to handle the error case, but in go you can accidentally ignore it.

I believe there is a vet check for this. So while the compiler won’t stop you from ignoring errors, it will tell you that you aren’t checking an error. Yes, you can ignore the error with _, but then it isn’t accidental.

Re: Gopher Wrangling: Effective error handling in Go

#49

Earlier quoted context omitted.

The killer feature of Rust's Result isn't actually the monad itself, it's the ? operator. Being able to concisely say "if there's an error, bail out by returning it" gets you pretty close to exception-level convenience with just a bit more explicit syntax showing where an error might come from.

you don't want exception-style "convenience", that's the whole point you want to be able to read code and see a single control flow ? subverts that core requirement

The problem with exceptions is that they can come from any line of code and cause a "return". Rust's question mark solves the issue because it marks which lines of code can cause a "return".

Therefore, you can always see see the control flow of a function.

Moreover, you can go even further if you really really really want a single control flow. You can write a clippy lint to disallow early returns (ban "return" keyword) and question marks. That said, I really don't think this is a good idea. The "return" keyword exists for a good reason.

Re: Gopher Wrangling: Effective error handling in Go

#50

Earlier quoted context omitted.

The Rust code you have isn't idiomatic. It's gar more likely to see: let greeting_file = File::open("hello.txt")?l vs file, err := os.Open("hello.txt") if err != nil { return fmt.errorf("faild to open hello; %w, err) } However, I would argue the distinction isn't just cosmetic. The compiler prevents me from not checking the error and blowing up the application with a nil pointer exception. The TFA even capes this pat…

Where is the error handling in your Rust code?

The `?` at the end of the Rust example expands into the equivalent of the Go `if err != nil` idiom.
Post reply on HN