For example:
err := doSomething()
if err != nil {
return nil, err
}
err = doSomethingElse()
if err != nil {
return nil, err
}
// Oops unhandled
err = doSomethingElseEntirely()
// A bunch of other stuff..
return nil, nil
Would much prefer "Either" with pattern matching, or something else that actually forces you to do something.Go forces you to think about failure just as much as success, and I find that fantastic for building robust software.
Errors happen, so you're forced to do something when they do. Errors aren't exceptional.
But more importantly to me, Go forces you to think about what a caller to your function might want to know about what went wrong. Errors in modern Go are for communication, not an explosion of "something bad happened, abort!"
A long time ago, errors in Go were very basic -- essentially just strings 99% of the time, and I think that's where some of the hate comes from. In the early days, I think it was deserved.
But nowadays, with the Go errors package (error chaining), errors are extremely powerful.
Good libraries will often return an error structure that provides more context than a stack trace would, e.g. os.LinkError: https://pkg.go.dev/os#LinkError
tl;dr if you're writing "if err != nil { return err }", you're holding it wrong.
Except, it doesn’t.
Forcing you to at least write boilerplate code for failures might be a nudge to think about them for some people, but it absolutely is not “forcing” you to think about it, and you can absolutely defer it with boilerplate while concentrating on the success path and never actually return to it.
res, _ := some_func(…)
But it's obvious that you're doing something naughty when you do.
edit: combating the overzealous auto-correct