Description
In a recent URLO post, someone saw the "no guarantees" paragraph in read_exact
, and this convinced them not to use it (and to instead use read
).
The post: (link)
Okay. That does means I should replace all read with read_exact? Since it said no guarantee I was hesitant to use it.
The paragraph:
No guarantees are provided about the contents of buf when this function is called, implementations cannot rely on any property of the contents of buf being true. It is recommended that implementations only write data to buf instead of reading its contents.
While the caution is (or at least was) legitimate, I think for today's rust it's a bit negative. And if this is a user's first real read
method they use, then I can 100% understand getting thrown off by this language.
I'd like to think we can reduce the caution necessary when using it, while still keeping the caution for implementors. Thoughts on replacing it with a more positive message, like the following?
This function may be called with any
buf
, and makes no requirements on the contents ofbuf
or any property about the contents ofbuf
being true. It is recommended that implementations only write data to buf instead of reading its contents.
The italicized "implementations" is taken from the documentation on read
, which reads:
No guarantees are provided about the contents of
buf
when this function is called, implementations cannot rely on any property of the contents ofbuf
being true. It is recommended that implementations only write data tobuf
instead of reading its contents.
I don't think it's necessary to modify the paragraph on read
, as it has much more overall content, as it also contains this following paragraph:
Correspondingly, however, callers of this method may not assume any guarantees about how the implementation uses
buf
. The trait is safe to implement, so it is possible that the code that's supposed to write to the buffer might also read from it. It is your responsibility to make sure thatbuf
is initialized before calling read. Calling read with an uninitializedbuf
(of the kind one obtains viaMaybeUninit<T>
) is not safe, and can lead to undefined behavior.
In addition, the read
documentation is big enough that users can skip over the "no guarantees" paragraph. Case in point, the user from the URLO thread above chose to use read
, while avoiding read_exact
, even though read
contains the exact same paragraph.
I'll end by saying I don't know the full history, but I think this might have had something to do with passing uninitialized byte buffers to read methods. I believe that it's been decided that passing in an uninitialized buffer is UB, though, so it shouldn't be as big of a concern. The current discussion of reading into uninitialized buffers is at 42788.
This issue has been assigned to @poliorcetics via this comment.
Activity
RalfJung commentedon May 14, 2020
I think I authored or at least reviewed the changes that made the
read
docs more clear. The docs are prepared for a future where the passing of an uninitialized buffer itself is not UB, but of course if you call arbitrary safe code (viaRead::read
) and give it an uninitialized buffer that is still unsound and can cause UB depending on what the code does. I was not awareread_exact
contains the exact same issue!Would it make sense to copy the longer explanatory paragraph to
read_exact
, and/or link to theread
docs to avoid duplication?poliorcetics commentedon Jul 18, 2020
@rustbot claim
ilyvion commentedon Jul 19, 2020
I'm not sure I understand the confusion. This paragraph:
applies to implementations of
Read
, consumers don't need to pay attention to that bit at all. As for the bit that applies to consumers;it just says to pass a regularly allocated
buf
and to not try being clever by using an uninitialized buffer.Rollup merge of rust-lang#74486 - poliorcetics:read-exact-doc-point-t…
daboross commentedon Jul 20, 2020
I don't think the text was ever incorrect, it's just that someone skimming the docs can read things incorrectly.
As I understand it, in the case I opened this issue for, the user certainly didn't read and understand the entire paragraph. They just saw "no guarantees", and decided this function wasn't the right thing to use.
I'm OK with needing people to read the entire doc, but I think this goes beyond that? Particularly, if someone misreads or doesn't understand the word "implementations" in the first sentence of the paragraph, it reads as literally not guaranteeing anything about the output. I thought this was overly harsh for something the majority of users shouldn't have to care about, especially when it's harsher than another function,
read
, which should be used much less often by end users.Plus, I think plenty of users who will encounter this before they understand proper terminology surrounding traits - "implementations" refers to someone implementing the trait, but that's not exactly obvious until someone's worked with rust for longer. And reading from a file is often a simple thing one might try to do before exploring more complicated aspects of the language? I guess I think it's totally understandable to misread this - even if they pay attention and try to understand the entire docs.
Maybe something like renaming read, like suggested in https://internals.rust-lang.org/t/poor-naming-of-read-write-i-o-methods/12685/13, would be a better long-term solution for getting people to actually use
read_exact
rather thanread
. But I think making the language less, well, scary onRead::read_exact
could mitigate this?I appreciate the changes in #74486, and I apologize for not being active on this issue. But I'd also argue that if this issue was ever valid, it still is - and this should be reopened.
mbxt commentedon Mar 10, 2024
I know this thread has been closed for a while, but maybe I can offer my two cents as someone who misread the documentation and recently encountered the same confusion:
The context switch from providing documentation to callers to providing documentation to implementers is only stated after the warning, after alarm bells had already gone off in my head, so in a sense, it's my mistake for getting distracted by those warnings and not reading more carefully, but on the other hand,
I think reordering from
to
could provide a simple win. Going one step further to
would have been even more clear, but I could see how from a certain perspective this might seem unnecessarily wordy, or might not be consistent with other documentation.
In hindsight, the documentation for
read_exact
now makes perfect sense, and it wasn't a matter of learning anything I didn't already know about traits, it was merely a matter of noticing the context switch and not getting tripped up by the warning.Rollup merge of rust-lang#122276 - RalfJung:io-read, r=Nilstrieb
Rollup merge of rust-lang#122276 - RalfJung:io-read, r=Nilstrieb
1 remaining item