-
Notifications
You must be signed in to change notification settings - Fork 18k
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
io: Copy godoc "returns ... the first error" is misleading #9744
Comments
io.Copy has to discard at least one error here. And it's debatable If we change it to return the Read error, then I think it shouldn't issue We could also interpret the docs in a different way. Because it's BTW, could network connections return (n, err) with n > 0 and err != nil? |
Technically, it doesn't necessarily have to discard one of the errors; returning an error that holds both underlying errors could be an option too, but it is probably not worth the added complexity. So I agree that it is reasonable to return just one of the errors in this situation.
This paragraph seems self-contradictory to me... I agree with the second half -- not issuing the Write call would be against the convention regarding how to handle io.Reader errors.
I see where you're coming from; it makes sense if "first error" is interpreted as in byte positions. E.g. with read error at byte index 1024, write error at byte index 512, the write error can be considered "first" even if the read error occurred earlier. The question is, first, whether that was the intent, and second, what people reading the docs think. For the first question, it may as well be the intent, and this way the error is actually correlated to the position (number of bytes successfully copied) that the error is returned together with. For the second question, I can only speak for myself, but it didn't occur to me that "first error encountered" could refer to something other than temporal/"happens-before" first... Given the current docs (and the established Go convention to process any "residual" data received together with a read error), my interpretation was that if I get a write error, I could assume that there was no (read) error prior to that. On the other hand, if I get a read error, I couldn't assume anything about what happened afterwards. Although I have to add that English is not my native language (but then, the same is true for a large portion of people reading the docs). Assuming the behavior is intended, I'm thinking that there should be a better way to put it that is clearer to a wider range of users, though I haven't managed come up with a good one -- I'll keep thinking.
You're right that syscalls don't directly expose this capability; I was assuming the case when using a buffering reader implementation that could aggregate results from multiple syscalls. |
It all depends on the meaning of "the first error". If you think it means the read, then it shouldn't continue to issue On the other hand, if you regard that a Read that returns (n, err) Making io.Copy return a new Error struct combining the two errors There are more corner cases in the design of io.Copy (for example, |
Yes, and my opinion is that it's quite a bit of stretch to call the error from Write the first error in this scenario, and that it is not what most people reading the docs would think. The way I interpret the docs is that the first error is returned (which in this situation would be the one from Read), and there may be further errors (e.g. from a subsequent Write) but those will be discarded.
I think it means the read, but as I've already said in my previous comment, I don't agree with this reasoning; not issuing the Write is contrary to the established Go convention, that is, contrary to what people reading the docs should be expecting.
I'd prefer not to introduce new terms ("successful"); we have enough confusion with the existing ones already. :) My primary issue is not which behavior is "correct"; it is that it's not doing what (I think) the docs say.
I'm aware of that, and I didn't mean to suggest changing it that way. I just pointed it out to emphasize that discarding some errors is not "inevitable", but is a result of a conscious design choice, favoring simplicity over "correctness"/"consistency", which I agree with. Applying the same rationale, even if the current implementation is deemed the more "correct" or "consistent" behavior, changing the implementation to match the docs (return Read error, discard any further) can be considered favorable to documenting the current behavior (which may require introducing new terminology such as "successful read"). In addition, in case the two errors share the same underlying cause, keeping the one that occurred first (in time) may be more helpful than the second.
I don't want more control, I just want it to do what it says (or, say what it does). |
TL;DR version:
|
I'm in favor of document this corner case. |
Right, I didn't consider that a behavior change would need to also involve ReaderFrom/WriterTo. |
go version go1.4.1 linux/amd64
linux/amd64 and playground
Use io.Copy where both Read and Write return error: http://play.golang.org/p/8pPVAVxQLi
The error from Read:
error#1
(According to godoc, Copy returns "the first error encountered while copying, if any.")
The error from Write:
error#2
Although the example may seem pathological, such situation could actually happen e.g. on network failure, and I believe that getting the error from Read is more helpful in general (in addition to being in line with godoc).
The text was updated successfully, but these errors were encountered: