Hacker News new | ask | show | jobs
by foldr 650 days ago
I think from a Go point of view, the lesson to be drawn from that is "don't defer a function call if you need to check its error value", rather than "defer needs to support checking of function return values".

In the example at hand, it really makes more sense to call Close() as soon as possible after the file is written. It's more of an issue with the underlying OS file API making error checking difficult.

In 99% of cases, the solution to this problem will be to use a WriteFile function that opens, writes and closes the file and does all the error handling for you.

1 comments

> the lesson to be drawn from that is "don't defer a function call if you need to check its error value"

Isn't the lesson here: If you must have a Close method that might fail in your API, ensure it can safely be called multiple times?

As long as that is true, you can approach it like you would any other API that has resources that might need to be cleaned up.

    f, _ := os.Create(...)
    defer f.Close()
    // perform writes and whatever else
    if err := f.Close(); err != nil {
        // recover from failure
    }
(os.File supports this, expectedly)

> the solution to this problem will be to use a WriteFile function

If it were the solution you'd already be using os.WriteFile. It has a time and place, but often it is not suitable. Notably because it requires the entire file contents to be first stored in memory, which can become problematic.

Certainly you could write a custom WriteFile function that is tuned to your specific requirements, but now you're back to needing to be familiar with the intricacies of a lower-level API in order to facilitate that.

Sure, that's an alternative, although it means there will be some code paths where the error returned by f.Close() becomes the error returned by the entire function and others where it is ignored (though you could easily log it). That might be fine, but you also might want to handle all the cases explicitly and return a combined error in a case where, say, a non-file-related operation fails and then the file also fails to close.
> becomes the error returned by the entire function

If you find the error returned by f.Close to be significant, are you sure returning again it is the right course of action? Most likely you want to do something more meaningful with that state, like retrying the write with an alternate storage device.

Returning the error is giving up, and giving up just because a file didn't close does not make for a very robust system. Not all programs need to be robust, necessarily, but Go is definitely geared towards building systems that are intended to be robust.

It obviously depends on the context. There's no general right or wrong answer to that question.