Earlier quoted context omitted.
this is especially true for everything related to error handling. I've never had to deal with a java codebase where exception were causing problems, but golang made me feel worrying about it from day 1. I really think they made the language a little bit too small.
If you have only worked in languages with exceptions, it's not surprising that you would struggle with Go's C-style error handling. I've grown to prefer it, as exception handling typically boils down to "not my problem" in most code bases. Go forces you to think through each error condition, which is an unusual amount of effort for people who may not be accustomed to it.
One is that it quickly becomes hard to find out where errors really came from. Consider this idiomatic code:
func MyFunc(input int) (output int, err error) {
if output, err = someOtherFuncA(input); err != nil {
return
}
if output, err = someOtherFuncB(output); err != nil {
return
}
// ...
}
If MyFunc returns an error it's not possible to know where it came from unless you know all about someOtherFuncA and someOtherFuncB and they return different kind of errors.
What's missing from the stdlib is a utility that wraps errors to reproduce what's essentially a backtrace. `return wrapError("someOtherFuncA", err)`The other issue is that (error) doesn't tell you what kind of errors are going to be returned. It's often useful to be able to classify errors as to respond to them accordingly. IO errors might be retryable but data-structure errors might be not. In the stdlib they use value comparison as a trick to classify errors combined with documentation of what exactly will be returned.