On Thu, Oct 27, 2022 at 06:23:31AM -0700, Gergely Brautigam wrote: > I was wondering what's the consensus these days on handling defer errors? > > Is it something like, overwriting the returned value, or using a list of > errors? > > Either: > > func test() (err error) { > defer func() { > if tmpErr := doSomething(); tmpErr != nil { > err = tmpErr > } > }() > > err = doSomethingElse() > return err > } > > Or: > func test() (errList []error) { > defer func() { > if tmpErr := doSomething(); tmpErr != nil { > errList = append(errList, tmpErr) > } > }() > > if err := doSomethingElse(); err != nil { > errList = append(errList, err) > } > return errList > } > > Or even something else entirely?
I think you're falling into a common trap: there's no need to have any sort of consensus here because what you have demonstrated are two approaches to tackle a problem, and they depend on what you're after. One could easily add other variations. For instance, often you want to Close() a resource on an error path out; calling Close might itself return an error, and sometimes this error is less severe than the "original" one. As an example, consider opening a network socket and then doing some setup on it: say, socket creation went OK but the setup failed, so you'd want to return the error about the failed setup operation, and if closing the socket on the way out fails for some reason, you could possibly ignore this error. Of may be you can log it. On the other hand, if, say, you had a file opened for writing, wrote some data to it, then some error has happened, and you're aborting the operation returning that error, and closing of the file on the way out fails, this might be a severe enough error because it might indicate some data which was written got lost. What to do about it? There's no ready answer. You could construct a custom error with a compound error message, like "error X has happened while Y, and also closing of F has failed during cleanup". You can also return a list of errors. Or create a custom type implenting the error interface which holds a list of errors. Since Go 1.13 you can also make chains of errors; say, in your second example you could do err = fmt.Errorf("doSomething failed with %s while handling %w", tmpErr, err) and then have callers use errors.Is / errors.As or whatever other approach to learn whether the error of their interest is in the error chain. Note that in ether approach with returning multiple errors, the callers are to be prepared to handle multiple errors; otherwise it's engineering for the sake of engineering which leads to nothing more than code which is convoluted for nothing. So I'd recommend to start small, use the simplest approach possible until you see clear need to use a more complex one, and then decide what looks/works best in a particular case. I know, this is a glib piece of advice, but it's really how the things are ;-) -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/20221027175042.uhaakvkgnmbvqmh4%40carbon.