3 ms·
Actually, stack traces are a very poor way to provide context. I can't count how many times I've worked with some library in ${LANGUAGE_WITH_EXCEPTIONS}, and h
by bheadmaster 3y ago
Actually, stack traces are a very poor way to provide context.
I can't count how many times I've worked with some library in ${LANGUAGE_WITH_EXCEPTIONS}, and had an exception print out a giant stack trace, only for me to realize that the stack trace is useless because the place where exception is raised isn't the place where the error actually happened, but is actually some wrapper/worker collector/other kind of indirection mechanism. In other words, stack traces are directly bound to call stacks, and call stacks don't necessarily contain all relevant context of an error - they only do so in case of simple, single-threaded programs.
Golang-style error-as-values actually provide real, human-curated context that is relevant to the operation at hand. They can be passed between goroutines, and are completely independent of any call stacks. That, in my opinion, makes them vastly superior to stack traces.
- the_gipsy 3y agoIt's true that stacktraces don't work out so well in many languages. But ironically in go they do seem to work fine in my experience. Adding a stacktrace to custom go errors do show me correct and useful traces across goroutines. I guess it's the fact that async is built into the language as a primitive or something. Regarding wrapping errors, if you don't provide a stacktrace or at least file:line, how do you actually map the error to source code? Do you just grep and pray that the message is unique enough?
- bheadmaster 3y ago> Do you just grep and pray that the message is unique enough? If you're new to the codebase, yes, grepping can get you a long way. In my experience, just following the error messages from the top (usually errors are printed only in the main function) is enough. Hypothetical example, if you have a file sync program, and you get an error "file sync failed: device Foo unreachable: connect error: quic://123.45.67.89/ i/o timeout", you can already mentally map where exactly the error has happened. The exact file and line should be easy to locate. Of course, if a codebase doesn't write descriptive enough errors, or just propagates them without context, error diagnosis is going to be difficult. But that's why Go encourages people to think about errors and not ignore them.