-
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
proposal: io: require io.Reader to return either n > 0 or an error #27531
Comments
I think if we wanted to do that we would also need to change the name of the method. We want Go 1 and Go 2 APIs to be able to coexist in the same program, and per https://research.swtch.com/vgo-import, that requires that “when you change a function’s behavior, you also change its name.” |
I think the (I didn't find a compelling reason the last time I checked: #24205 (comment).) |
Though undocumented, the EDIT: I just checked. |
surely the contract, put as a conversation, is... reader.Read == 'i want some bytes in this buffer, let me know how many you have put in it and if there is a problem that effects me repeating this action'. the reader Reads without knowledge of how many are available, isn't this isolation a fundamental point of a reader. |
It is interesting that https://golang.org/pkg/io/#Reader discourages this but allows it.
It appears this was considered when designing the io package. Perhaps to allow readers where Read can be used to poll for data to be read instead of blocking? It's unidiomatic for sure but that's the only reason I can think of. And anyone who definitely wants to block uses |
@nhooyr The guidelines for |
This proposal has been added to the active column of the proposals project |
I don't see a way to do this compatibly. There exist implementations that can return zero-length successful reads. Any reader that is reading and stopping on packet boundaries might do that, for example. This is another example of something that we can't easily change without invalidating all the implementations in the wild, which means we can't really change it. |
Based on the discussion above, this proposal seems like a likely decline. |
No change in consensus, so declined. |
If returning |
A reader that returns |
@ianlancetaylor what about when working with CGO and compression libraries. I was under the impression you want to avoid blocking the OS thread and I'd see this as a valid use-case where it could return For example this library https://github.com/DataDog/zstd Edit: Wanted to add if there's a better approach of some sort, I'm more than open to implementing it. Just from my understanding the C library itself does not have a way to safely block and hook that with Go. |
@ethan-gallant You possibly should create an issue in DataDog/zstd (ideally, with a repro). I agree with @ianlancetaylor, returning 0-bytes 100 times in a row is suspicious. Normally, compressing library reads uncompressed data from input stream, does its compression magic and writes result to the output. Such logic is not supposed to produce many 0-bytes results. |
Some compression formats have the concept of a "sync flush" where a special block is a signal to the decompressor that it should report all uncompressed data to the application. If a decompression stream contains a series of back-to-back sync flush blocks without any data in-between, I would expect it to still read (0, nil) a number of times repeatedly. |
Agreed, additionally 100 is a very ambiguous catch-all case. What makes 100 so significant here, why not 1000? Who's to say how frequently a consumer may call read or the frequency at which they do it. |
My opinion is that we should leave bufio as is unless and until somebody finds a real world problem. The current code was worked out in the discussion on https://go.dev/cl/76400048. |
@ianlancetaylor the real-world problem is that using While the documentation says "this is discouraged" it does not state it is unsupported. |
@ethan-gallant What I mean by a real-world problem is a real existing Go program that breaks because of how bufio currently behaves, and would be fixed if bufio's behavior changes. I would also be willing to accept a real existing Go program that has extra code to work around the current bufio behavior. A |
This library when compressing large images and reading them with bufio.Reader produces the error. From what I gather it's related to how the library interacts with CGO and the ZStd library. Not sure if there's an alternate way, but the zstd library does have a similar implementation that doesn't translate well into Go bindings for this reason. |
When in actual practice are those packages going to return |
Whenever you're compressing a large object, like a database backup or container image that exceeds 600MB on a slower CPU. |
I'm sorry, I don't understand how that could happen. Can you show an example? Thanks. |
An example is a reader that returns Maybe it's isolated to https://github.com/DataDog/zstd but regardless, it's documented that returning |
As I understand, @ianlancetaylor wants a real-world usecase, not an artificially crafted reader that would infinitely return If you say that https://github.com/DataDog/zstd is capable of doing that, do you have a repro code? |
Today the
Read
method of anio.Reader
is allowed toreturn 0, nil
. It is uncommon and discouraged:It is so uncommon that it is hard to remember to deal with this case when using an io.Reader. All correct calls to
Read
need to be wrapped in a loop that tries multiple times, and after some ill-defined cutoff, report an error likeio.ErrNoProgress
. Consider the correct example of reading from bufio.Reader:For Go 2 I propose we change the contract of
io.Reader
so implementations are required to return eithern > 0
or a non-nil error.The text was updated successfully, but these errors were encountered: