Automatic stack capture for exceptions is something my language could conceivably do on my behalf.
Writing even 3 lines of code per function to propogate up the error is a huge pain, especially because it pollutes the return type -- MustWhatever() in go is much easier to use than Whatever() returning (type, err)
I guess it's part of the Go philosophy - more dynamic logging would most likely incur relatively higher performance costs.
The ? operator is better than nothing, but I still need my error types to match all the way up the stack
Forgetting that a function returns an error:
...
foo() // foo returns an error that isn't being handled.
...
Forgetting to check the error returned by a function. Note a linter won't pick this up since the err variable is used later. ...
err := foo()
err = bar() // The previous error will go unhandled.
...
Accidentally typing return nil instead of return err: ...
if err != nil {
return nil
}
...
And in the case of the errors library, there's times where I will call a builtin function that returns an error and forget to call errors.WithStack. Every once in a while I'll come across an error without a stack trace and I'll have to hunt down where it came from: ...
err := json.Unmarshal(bytes, &obj)
if err != nil {
return err // should be errors.WithStack(err)
}
...
All of these issues look just like normal bug free Go code. On the basis that I've introduced more bugs this way, I prefer Python style error handling by far.I think there are a lot of schools of thought on this precisely because it is a difficult problem to solve: it requires getting a bunch of programmers to agree about how the edge cases should be handled, and that's no small feat.
Composition: Errors as values means it is easy to write functions to deal with them. Errors as exceptions means invoking special language constructs. And program termination doesn't compose well. Library authors always avoid panics. Generally only applications are good at deciding when to panic and when to catch a panic.
Hidden: how do you know if a function panics? If it returns an error, I see that in the type signature and I can be forced to handle it by linting tools. People seem to not like Javas checked exceptions, but I think that like most things Java it had to do with some of the implementation details, I think the concept is much preferable to hidden exceptions/panics.
For the socket disconnect for example, maybe a child process maintains a connection to the parent manager process. A socket disconnect is absolutely unexpected then and explicitly handling it adds noise.
You can reach out to us on slack (gorotisserie.slack.com/archives/CS13EC3T6) for additional comments and feedback. Thanks!
One other issue I've struggled with is in propagating errors across goroutines. If an error is created in the child routine, `runtime.Callers` doesn't include any stack frames from the parent. Assuming the parent wraps the error, it sounds like Eris would give you at least one line of the parent stack trace. Does it handle this specifically by including all of them?
It seems to have a bit of a cleaner presentation in the error stack -- Its an array, which feels nicer than a string.
It's just that she isn't a major goddess, and is famous only for her "apple of beauty" trick. And outside classical scholars, that's arguably via Principia Discordia.
So I'm curious.