I've mostly evolved to making err a named return parameter, and inverting the err != nil check. For example: func foo() (err error) { var x any if x, err = bar(); err == nil { err = baz(x) } if err == nil { err = bat() } if err != nil { err = fmt.Errorf("%w doing foo ", err) } return } This feels somewhat cleaner to me, in particular by combining error handling (in this case just a simple wrap) in a single place at t…
Some other variants I've played with: func foo() (err error) { var x any if x, err = bar(); err != nil { goto fooError } if err = baz(x); err != nil { goto fooError } if err = bat(); err != nil { goto fooError } return fooError: return fmt.Errorf("%w doing foo ", err) } Or: func foo() (err error) { defer func() { if err != nil { err = fmt.Errorf("%w doing foo ", err) } }() var x any if x, err = bar(); err != nil { re…
in generated code, sure -- that's why it exists, to support codegen
it's sometimes abused to manage for loop control flow
but the stdlib is definitely not some platonic ideal -- it's a decade+ old code base which has suffered all of the indignities of organic growth
it's full of bad code and terrible anti-patterns
(good stuff, too!)