-
Notifications
You must be signed in to change notification settings - Fork 17.7k
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
proposal: io/ioutil: add WriteNopCloser #22823
Comments
This comment has been minimized.
This comment has been minimized.
The permutations go from viable to esoteric 😏:
|
I support this proposal out of practical experience. I just ran across a use case where I needed just this function, and settled for a suboptimal design because it didn't exist. My application produces a log file whose path is configurable via environment variable. If the variable is provided, it's assumed to be a file path and an func main() {
logWriter := GetLogWriter()
defer logWriter.Close()
}
func GetLogWriter() io.WriteCloser {
if path, ok := os.LookupEnv("LOG_PATH"); ok {
if file, err := os.Create(path); err == nil {
return file
}
}
return ioutil.WriteNopCloser(ioutil.Discard)
} But, having no trivial way to get an func main() {
var logWriter io.Writer = ioutil.Discard
if path, ok := os.LookupEnv("LOG_PATH"); ok {
if file, err := os.Create(path); err != nil {
panic("sad day")
} else {
defer file.Close()
logWriter = file
}
}
} This works, but it's not great. Specifically, the conditional Footnotes
|
Change https://golang.org/cl/175779 mentions this issue: |
Would love to see this PR accepted! |
Just ran across a use case for this as well. I have a function that returns a WriteCloser to be used for caching. If the cache file can't be written to I still want everything to succeed without having to do any major alternative paths in the request handler so instead I made a WriterCloser out of Discard basically how this is and log the cache failure separately. |
To restate the argument in favor of adding this, the situation where it comes up is that you need to implement an interface method that is defined to return an io.WriteCloser. And all you have is a io.Writer. The implication is that the caller calls Close to say "all the writes are done", which usually triggers processing of the collected writes. So nopping out Close would be an odd thing to do or to make very easy. The specific case of ioutil.Discard is unfortunate: we probably should have defined that as its own type instead of an io.Writer, and then it could be changed to have a Close method. We could still do that - add a Close method on the underlying implementation - and document that it is safe to use ioutil.Discard.(io.WriteCloser). Are there examples other than ioutil.Discard? The situation is different from Read/ReadCloser because closing a reader is more of a courtesy, compared to "now do something with everything I wrote" for closing a writer. WriteNopCloser may still be worth adding but we should understand the reasons better first. |
I saw an interesting use of func EncryptWithArmor(dst io.Writer, recipients ...Recipient) (io.WriteCloser, error) { Internally this is implemented by wrapping the user-provided writer in types that handle encryption and base64 encoding, plus, at the bottom of the chain, the equivalent of a // stream.Writer takes a WriteCloser, and will propagate Close calls (so
// that the ArmoredWriter will get closed), but we don't want to expose
// that behavior to our caller.
finalDst = format.NopCloser(dst) |
@rsc If you were replying to me, that's essentially what I was getting at. In my case I was making a basic file system cache and I wanted to maintain the illusion to the caller that everything passed even if say the program didn't have write permission or something so I put a no-op close method on discard and return that as a WriterCloser. If perhaps I wanted to have the option to compress my cache file with |
@magical, arguably the example in
Then the implementation in |
Two weeks ago I asked about motivating use cases. So far there has only been one, which on closer examination turns out not to be that compelling. The fundamental problem is that Close on a WriteCloser is very often semantically meaningful, whereas Close on a ReadCloser often has very little semantic meaning. So a nop'ed ReadCloser is helpful while a nop'ed WriteCloser is more often a mistake. Based on the discussion so far, this seems like a likely decline. Leaving open for a week for final comments. |
No final comments, so declining. |
The type
ioutil.NopCloser
allows us to add a no-opClose
to an existingReader
when aReadCloser
is required.For symmetry, there should also be a
ioutil.WriteNopCloser
to do the same forWrite
.The name can be argued about. Get out your bikeshed paint brushes.
The text was updated successfully, but these errors were encountered: