4 ms·
Error handling is one of my favorite parts of Go. The haters can rip `if err != nil { return fmt.Errorf("error doing thing: %w", err) }` from my cold dead hands
by veggieroll 1y ago
Error handling is one of my favorite parts of Go. The haters can rip `if err != nil { return fmt.Errorf("error doing thing: %w", err) }` from my cold dead hands.
- ummonk 1y agoYou don't use gofmt?
- tom_ 1y agoThe whole point of gofmt is that you type in whatever you like and gofmt sorts it out for you. So if you're typing your code in a HN comment box, you'd surely just enter it roughly like that - though i recommend not even including the syntactically irrelevant spaces shown here. Your space bar does have a MTBF you know, and it's measured in activations... let gofmt take the strain. It can waste your screen space for you! gofmt is the good bit about working in Go. Pretty much everybody uses it, and so you can use it too. Some other languages have similar tools, but they're not as pervasive, so it's far too easy to end up in a situation where you can't use the tool because it would just make too much of a mess of the inconsistently manually-formatted stuff that's already there.
- School-Cotton 1y agorustfmt is at least as pervasive as gofmt.
- thayne 1y agoError handling is the thing I hate the most about go. And none of the serious proposals I've seen would remove your ability to continue using `if err != nil`
- veggieroll 1y agoI have yet to see a proposal that retains what I love about the status quo: conscientious error handling. The language’s status quo forces everyone to think about errors more deeply than in other languages and acknowledges that the error case is as critical and worthy of the programmer’s attention.
- sedatk 1y ago> forces everyone to think about errors more deeply than in other languages Not really. Rust also forces you think deeply about errors but don't bother you with verbose syntax. I think Swift was also similar.
- thayne 1y agoSomething like: x := FallibleFunction() ? err -> return fmt.Errorf("something happened %v", err) Doesn't really change that, but significantly reduces the amount of noise from error handling boilerplate. And (most importantly to me) reduces the amount of vertical space taken up by error handling code, which makes it easier to follow the happy flow.
- RVuRnvbM2e 1y agoReduces the vertical space by vastly increasing the horizontal space and inserting line noise into the syntax. I don't even understand what that code would do.
- deleted 1y ago[deleted]
- danenania 1y agoI think the issue is that "easier to follow the happy flow" basically also implies "easier to ignore the unhappy flow", and this is what a lot of people who have come to like Go's approach react against. We like that the error case takes up space—it's as important to deal with correctly as the happy path, so why shouldn't it take up space?
- thayne 1y agoIs it 3x as important? Because currently, for a single line of happy path code you often have 3 lines of error handling code. And while handling errors is important, it is also often trivial, just optionally wrapping the error and returning it up to the caller. I agree it is good for that to be explicit, but I don't think it needs to take up more space than the actual function call. In my experience, the important error handling code is either at the lowest layer, where the error initiall occurs, or at the top level, where the error is reported to the user. Mid level code usually just propagates errors upwards.
- catlifeonmars 1y agoHow do you feel about v, err := foo.Open() // … defer func() { if closeErr := v.Close(); closeErr != nil { err = fmt.Errorf("while closing %w: %v", err, closeErr) } }() // … When you’re writing something trivial/pure, Go’s error handling is fine, if maybe a tad bit verbose, but it quickly becomes nightmarish when you start to do nontrivial things that are typical for systems programming. FWIW I love Go, it’s my daily driver for most things. I still think it can get messy far too quickly
- database64128 1y agoJust write `defer v.Close()`? In almost all cases, `close(2)` errors can be safely ignored. Rust also does this: https://github.com/rust-lang/rust/blob/792fc2b033aea7ea7b766e38bdc40f7d6bdce8c3/library/std/src/os/fd/owned.rs#L169-L196 https://github.com/rust-lang/rust/blob/792fc2b033aea7ea7b766...
- catlifeonmars 1y agoI don’t think you want to do this for files you’ve opened for writing. In fact it’s quite common to “commit” on close, at least from what I’ve seen.
- database64128 1y ago> In fact it’s quite common to “commit” on close, at least from what I’ve seen. close(2) does not "commit". You have to call v.Sync() (i.e. fsync(2)) for that. From man 2 close: A successful close does not guarantee that the data has been successfully saved to disk, as the kernel uses the buffer cache to defer writes. Typi‐ cally, filesystems do not flush buffers when a file is closed. If you need to be sure that the data is physically stored on the underlying disk, use fsync(2). (It will depend on the disk hardware at this point.)
- catlifeonmars 1y agoI think we’re talking past each other. I was not talking about file descriptors; rather I was talking about the fact that it’s common for Go libraries to do interesting and useful things when you call the `Close()` method on a type. `Close()` is idiomatic go for resource cleanup. You might wait until close to populate a length and or checksum field in a message header. Or close could submit a buffer of log events to a remote aggregation endpoint. I’m not saying I agree with APIs that are designed that way, but it’s common enough that you should assume the error return value is significant unless you know otherwise (for Go)