7 ms·
Show HN: Error return traces for Go, inspired by Zig
- kaba0 3y ago[flagged]
- deleted 3y ago[deleted]
- packetlost 3y agoExceptions are only better than C style error return numbers but worse than pretty much every other model of error handling we have today.
- riku_iki 3y agoThere is an opposite opinion on this
- mordechai9000 3y agoI just picked up Go and thought I might use it for Advent of Code, to help gain some familiarity. The error handling kind of threw me off, though. I am coming from typescript most recently, and I think crashing on unhandled errors is a good thing. I have bad memories of perl doing unintended things after failing to catch an error. But I am willing to go out of my comfort zone. I think I'll probably have to find some linter configuration that will squawk when an error is ignored, though. Just for my own sanity.
- jerf 3y agoThe "standard linter" in Go is https://golangci-lint.run/ https://golangci-lint.run/ , which includes [1] the absolutely-vital errcheck which will do that for you. For an Advent of Code challenge you may want to turn off a lot of other things, since the linter is broadly tuned for production, public code by default and you're creating burner code and don't care whether or not you have godoc comments for your functions, for instance. But I suggest using golangci-lint rather than errcheck directly because there's some other things you may find useful, like ineffassign, exportloopref, etc. I highly recommend using Go with linters... but then, I highly recommend using any language with all the lint-like support you can get from the very beginning of any project, so I wouldn't read too much into that. [1]: https://golangci-lint.run/usage/linters/ https://golangci-lint.run/usage/linters/
- kaba0 3y agoBased on what exactly? I do think that e.g. rust’s error handling is quite okay with proper algebraic data types, but (checked) exceptions are similarly safe and ergonomic to use. The worst is without doubt the C style, whose legacy Go happily lengthens by doing the exact same thing, but natively in the language.
- mrkeen 3y agoChecked exceptions are not ergonomic. Whatever other benefits they might have are lost when every Java developer rethrows every checked exception as a more ergonomic RuntimeException.
- kaba0 3y agoStill better than losing an error case. But java’s solution is not the most ergonomic, no one was talking about that implementation.
- packetlost 3y agoWhat checked exception implementation do you have in mind then?
- riku_iki 3y ago> Checked exceptions are not ergonomic. its about the same ergonomics as rust error handling. Its just many people don't like to check exceptions, similarly many people write python code without explicit types.
- da39a3ee 3y agoI read the README but I'm not understanding yet why the return path might be what you want. The stack trace at error creation sounds more useful.
- prashantv 3y agoThe stack trace and return path are pretty similar if the flow goes through function calls on a single goroutine, but if errors propagate across goroutines or across different stacks (E.g., via channels), then it can miss some useful details. Here's an example that compares them: https://pkg.go.dev/braces.dev/errtrace#readme-comparison-with-stack-traces https://pkg.go.dev/braces.dev/errtrace#readme-comparison-wit... Since the HTTP library uses a separate goroutine to create connections, the stack trace at creation time doesn't have details about the user request that triggered the connection.
- Kharacternyk 3y agoThe logo is awesome. Has an artist been hired to create it?
- abhinavg 3y agoThanks! No, just one of the maintainers with a free evening.
- Eun 3y agoCan you explain why we should this over https://github.com/pkg/errors https://github.com/pkg/errors?
- para_parolu 3y agoEven this package is not needed anymore
- dagss 3y agoHow do you get stack traces of errors?
- randomdata 3y agoThe same way you get stack traces of names, email addresses, random numbers, etc. It is funny how the word 'error' leaves some suddenly forgetting how to write software.
- abhinavg 3y agoThe README covers the idea behind errtrace in more details, but the primary difference is in what is captured: pkg/errors captures a stack trace of when the error occurred, and attaches it to the error. This information doesn't change as the error moves through the program. errtrace captures a 'return trace'--every 'return' statement that the error passes through. This information is appended to at each return site. This gives you a different view of the code path: the stack trace is the path that led to the error, while the return trace is the path that the error took to get to the user. The difference is significant because in Go, errors are just plain values that you can store in a struct, pass between goroutines etc. When the error passes to another goroutine, the stack trace from the original goroutine can become less useful in debugging the root cause of the error. As an example, the Try it out section (https://github.com/bracesdev/errtrace/#try-it-out https://github.com/bracesdev/errtrace/#try-it-out) in the README includes an example of a semi-realistic program comparing the stack trace and the return trace for the same failure.
- 3y ago
- pixelpoet 3y ago(Aside about Zig, sorry. Although this applies to Go as well, I think?) Urgh I am so keen to switch to Zig but their attitude towards having vector operators just completely kills the viability for me as a graphics programmer. I've asked in their Discord, Andrew Kelley himself passed on commenting (I know his stance, every C++ dev wants their fav feature), but the reality remains that it's just infeasible to do with a DSL so it's just the wrong language for writing graphics code.
- Night_Thastus 3y agoI'm a C++ dev, could you explain a bit of what is missing in Zig for vector operations? Does Zig not have operator overloading?
- klyrs 3y agoNope, no operator overloading. As I understand it, the philosophy is to not hide O(n) behavior behind notation that looks O(1).
- Night_Thastus 3y agoStrange. How is that different from say, a function call? A function may look like a single O(1) operation from the input/output/name, but actually do something much more complex. That seems like the same thing to me, and very common. (and frankly I'm not sure that could even be avoided)
- klyrs 3y agoI didn't mean to volunteer to defend this choice, but without investigating a function you can't really support an opinion about its runtime. A language can make such promises about its basic syntax however. Perhaps I'll rephrase how I understand the philosophy: if it's a function call, it should look like a function call. Operator overloading breaks that. That said, this isn't my hill to die on. Edit to clarify my final sentence there: I have zero interest in debating this any further. Pixelpoet, if you're going to be so fussy, go read Harvey and van der Hoeven and stop trying to win language fights, they're tedious.
- Vanclief 3y agoWhile from a first instance, this package seems a bit overkill, I think the idea is interesting and is something that can be improved for Go. I also felt that Go errors where too bare-bones, so I developed a small package (https://github.com/Vanclief/ez https://github.com/Vanclief/ez) based on an awesome post that I saw here once. I use this package in all Golang code I touch.
- zgk7iqea 3y agogo is step by step reinventing exceptions
- wwarner 3y agogo basically has exceptions with panic & recover. and it’s perfectly simple to add stack traces to errors, should you want it.
- lsaferite 3y agoThat completely misses the fact that you need the providers of the code several layers away from you to make those choices and they frequently don't. I can add stack traces and raise panics all day long in my code and it will never help me trace a deep error in my system. The collective blindness to that in the go world is staggering.
- alphazard 3y agoExceptions typically unwind the stack, producing a stack trace similar to what certain Go error types already do. Go's panic does actually unwind the stack. In a sense, Go has had Java/Python style exceptions, from the beginning, through panic and recover. This project distinguishes itself from that pattern in the README. As far as error handling is concerned, errors as values is the modern thinking. Go is not behind the times here. If you squint, the `(T, error)` return type is very similar to Rust's `Result`, and the `if err != nil` idiom is basically Monadic control flow.
- tialaramex 3y ago> If you squint, the `(T, error)` return type is very similar to Rust's `Result` This requires the kind of squinting where 9 x 9 = 81 is basically the same as 9 + 9 = 18 right? I mean, they're roughly the same symbols, albeit one at slightly different angle, and in a different order... Result is a sum type, as are a lot of key things in Rust. Take the Rust type Result<bool,()> - this has three possible values, Ok(true), Ok(false), Err. The analogous Go product type has four possible values, (false,false) (false, true), (true, false) and (true, true).
- stirante 3y agoWe actually did something similar in Go here: https://github.com/Bedrock-OSS/go-burrito https://github.com/Bedrock-OSS/go-burrito I guess the difference we try to make is that we really wanted to make errors that are understandable by users. Each time the error is returned we try to wrap it with an information where and why.