-
Notifications
You must be signed in to change notification settings - Fork 17.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
os: codifying behavior of *os.File Close() more than once #20705
Comments
I don't think this should be encouraged. People will cargo-cult the practice to other io.Closers which might not handle it well. |
My main counterpoint to that is that the |
The issue is that the alternative to not double-closing a file is either unsafe (ignoring the error on func helloWorld() error {
f, err := os.Create("/tmp/notes.txt")
if err != nil {
return err
}
defer func() {
if f != nil {
f.Close()
}
}()
if _, err := io.WriteString(f, "hello world"); err != nil {
return err
}
err = f.Close()
f = nil
return err
} As was pointed out by a coworker, common lisp has a good specification for what happens in this case:
|
To elaborate: there are two kinds of behavior which would result in that double-close pattern being broken:
Documenting that it will return an error rather than causing bugs or a |
I don't think we should generalize, this issue is specifically about Calling |
Looks like it was already done in #32427 and https://golang.org/cl/180438. Going to close this then. |
Thanks for noticing. |
(Current as of Go version 1.9 beta 1)
I wrote a blog post recently discussing whether it's appropriate to
defer f.Close()
on writable files. In discussion that followed afterward, there was the suggestion to bothdefer f.Close()
to ensure that things were cleaned up, but also to explicitly to callf.Close()
at the end and check errors there. I'm going to call this pattern the "double-close." It'd look something like this:In practice this works well, but it's not well-defined in the docs. The docs for
io.Closer
say, "The behavior of Close after the first call is undefined. Specific implementations may document their own behavior." The docs for*os.File Close()
say nothing.Under the covers, calling
Close()
first checks to see if the underlying file descriptor is -1 and returnssyscall.EINVAL
in that case. Otherwise it closes the file descriptor and sets it to -1. This makes it safe (though not idempotent) to callClose
multiple times, and since it's deferred the second time, it's fine to discard thesyscall.EINVAL
error value.From the discussion that followed my post, it would seem that this is already in fairly wide use in the wild. I would like for the documentation to call this fact out, as it'd suggest that the double-close is a valid practice and unlikely to break in the future.
The text was updated successfully, but these errors were encountered: