6 ms·
Old and busted: func printSum(a, b string) error { x, err := strconv.Atoi(a) if err != nil { return err } y, err := strconv.Atoi(b) if err !=
by conroy 8y ago
Old and busted:
func printSum(a, b string) error {
x, err := strconv.Atoi(a)
if err != nil {
return err
}
y, err := strconv.Atoi(b)
if err != nil {
return err
}
fmt.Println("result:", x + y)
return nil
}
New hotness:
func printSum(a, b string) error {
x := check strconv.Atoi(a)
y := check strconv.Atoi(b)
fmt.Println("result:", x + y)
return nil
}
- spyspy 8y agoOnly seems useful when you have a function and want every error handled the exact same way, and don't have any requirement to add context the way https://github.com/pkg/errors https://github.com/pkg/errors does.
- ianlancetaylor 8y agoRead the design draft (https://go.googlesource.com/proposal/+/master/design/go2draft-error-handling.md https://go.googlesource.com/proposal/+/master/design/go2draf...). The issues you raise are addressed.
- spyspy 8y agoNot quite. You'd need to write new `handle err { ... }` blocks for every new context, like how they have one in the for loop. In effect you're just moving the handling of the error away from the place it occurred, which is not optimal. As someone who writes Go every day I don't see this strategy effectively cutting down on boilerplate core or adding clarity.
- tracker1 8y agoWhile this is true, more often than not, in lower-level functions you want errors to bubble up. For example, in most Node.js code, the first line in each callback raises the error to the callback, or likewise throws up in a promise/async chain. Beyond this, there's no reason you can't add additional context and/or wrap the original error before returning your own error. With this additional syntax and the addition of generics, I'm far more likely to take up go. Up to this point, I'd only toyed with it a little, because it just felt so cumbersome to actually get stuff done compared to node. Beyond that, dealing with web-ui, if I'm going to take on a cognitive disconnect for a back-end, I want as little friction as possible.
- spyspy 8y agoMy point is that using this to wrap context around errors is even more verbose than what's available/common today, since you either settle for one wrap for the whole function or you have to define multiple `handle` blocks.
- tracker1 8y agoDoes the "old" way no longer work?
- dvlsg 8y agoI'm in the same boat as you. Error handling and code generation (to support the lack of generics) in go always left a poor impression on me. I ended up going back to node for work, f# or typescript for personal projects. These two changes alone are enough to get me to pick go back up.
- deleted 8y ago[deleted]
- reificator 8y agoWhy the handler function over something like Rust's propagation operator? [0] I see that it adds significant flexibility, but at the cost of verbosity and a new keyword that largely conflicts with one of Go's niches right now, web servers. And that flexibility seems likely to go unused in my experience. I would be shocked to see anything other than `return err` inside that block. Sure errors are values and all that, and maybe I'm just working on the wrong codebases or following worst practices. But generally I see three approaches to errors in Go code, in order of frequency: 1. Blindly propagate down the stack as seen here. "It's not my problem- er, I mean, calling code will have a better idea of what to do here!" 2. Handle a specific type of error and silently recover, which does not typically need a construct like this in the first place. 3. Silently swallow errors, driving future maintainers nuts. This seems to only really help #1, but `return thingThatCanError()?.OtherThing()?` can handle that just as well. [0]: 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...
- DannyBee 8y agoI believe this is explicitly discussed in the doc: https://go.googlesource.com/proposal/+/master/design/go2draft-error-handling-overview.md https://go.googlesource.com/proposal/+/master/design/go2draf...
- bvinc 8y agoTheir discussion of Rust's error handling is woefully incomplete. They seem to think that the only thing that exists is the ? operator, which will return your error early, or a match statement, which is verbose. It misses some important aspects of rust's error handling. 1. There is a typed conversion between one type of error and another, which can keep context. 2. There are traits which can extend error types. 3. Backtraces can optionally be kept on (at a performance hit during errors of course). I have a lot of code written that looks like this, using the excellent "failure" crate, which allows optionally to add context to any error: file.seek(SeekFrom::Start(offset)) .context(format!("failed to seek to {} in file", offset))?; You get explicit errors, minimal code, optional error context. It's pretty perfect.
- jerf 8y agoIn your new hotness, I believe that handler is already implicit, so you can just leave it off. What I am still curious about, and can't see whether or not is possible from the current draft (possible I've just skimmed too hard) is whether printSum can become: func printSum(a, b string) error { fmt.Println("result:", check strconv.Atoi(a) + check strconv.Atoi(b)) return nil } Possibly with an addition paren around the check. (I'm just using this as an example; in this case I probably would assign x & y on separate lines since in this case this saves no lines, but there are other cases where I've wanted to be able to call a function that has an error but avoid the 4-line dance to unpack it.)
- ianlancetaylor 8y agoYes, what you write should work with the current draft.
- jerf 8y agoCool. It isn't something I'd want to abuse, but there are places in my code where it would clean things up nicely, too.
- cyphar 8y agoIt can, and this is mentioned in the error chain design doc[1]. [1]: https://go.googlesource.com/proposal/+/master/design/go2draft-error-handling.md https://go.googlesource.com/proposal/+/master/design/go2draf...
- webkike 8y agoThat should be possible because check is an expression
- millstone 8y agoSerious question: why is the error return from Println not handled?
- reificator 8y agoThere are two main reasons: 1. Many developers learn the print funcs before they really start paying attention to errors as return values, and so never think to check what it returns. 2. If println is failing, things are going very wrong. It would probably be more ergonomic to just have it panic in most cases, because if it errors out then what are you honestly going to do to recover gracefully? Just let your surrounding infrastructure handle it, whether that's restarting the process, starting a new container somewhere else on the cluster, or whatever.
- skybrian 8y agoIf stdout is unavailable, should that really be fatal? Perhaps it should be considered an unusual equivalent to piping to /dev/null.
- reificator 8y agoWhich is the current practice of ignoring errors from `fmt.Println()`.
- deleted 8y ago[deleted]
- jerf 8y agoIn general, catching errors when there is simply nothing useful to do with them isn't that useful. If the world is so broken that printing isn't working, it probably isn't the print failing that you care about. Even the errcheck linter, which I use in all my serious code, doesn't make you check the error from basic print statements like that. (Fprint it makes you check. But not just Print.)
- mike_hearn 8y ago