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
read/read_fully/read_partial/unbuffered_read behavior inconsistent and design unclear #1276
Comments
We'll probably remove For the others:
But it's true that we need to better design these methods. |
There is an inconsistency with the above proposal which would be confusing for anyone trying to learn the API.
I propose that read always reads the full amount requested
And read_partial returns whatever data is available
read_fully can be retired. |
Let me annotate that read_partial should block if there are 0 bytes available. |
We were thinking something along this line. These two methods, the ones that every IO must implement, read partially: - read(slice : Slice(UInt8)) : Int32
- read(slice : Slice(Char)) : Int32 Every other read-related method reads fully, and this is the consistent part: - read_fully(slice : Slice(UInt8)) : Nil
- read_fully(slice : Slice(Char)) : Nil
- read_to_end : Slice(UInt8)
- read_chars_to_end : Slice(Char)
- read_string_to_end : String # the current read()
- read(count) : Slice(UInt8)
- read_chars(count) : Slice(Char)
- read_string(count) : String # the current read(count) The convention is that We will also remove
|
@technorama Any opinion on the above methods, types and names? |
I am confused about the need for Slice(Char) vs Slice(UInt8) vs String. There seem to be too many types but maybe I am ignorant on the intended usage. Please correct me where I'm wrong.
|
read_nonblock can be useful with multiprocessing. One example is nginx and forking. The loop is similiar to:
Currently it can only be done with forking. Similar things can be done in the future with websocket or other servers/services when multithreading is available. |
That's a case for accept_nonblock, perhaps not read_nonblock. Maybe there isn't one. |
The methods that accept But @waj noted that in Go there's no |
We finally decided to do it like this: # partial read
- read(slice : Slice(UInt8)) : Int32
- read(slice : Slice(Char)) : Int32
# full read
- read_fully(slice : Slice(UInt8)) : Nil
- read_fully(slice : Slice(Char)) : Nil
- read_to_end : String
- read(count) : Slice(UInt8)
- read_chars(count) : Slice(Char)
- read_string(count) : String |
There's still a discrepancy in behavior and naming.
Here's an example of what can go wrong. Expect lots of confusion even when not refactoring.
|
You could make read_to_end as a Slice(UInt8) is useful in a variety of protocols.
|
I think I agree with the Regarding methods to get the full binary content into memory, we'd like to discourage that and that's why we removed those overloads from the list. Reading as string is also questionable but sometimes convenient. |
I'm closing this, the only |
This is still an issue basically, it's still inconsistent, Because of https://github.com/crystal-lang/crystal/blob/master/src/io/file_descriptor.cr#L225 it's not possible to request up to n bytes and return immediately. In other words there's no way to check whether there's data to read. Not even So we do lack an interface that
Alternatively we lack an interface that returns the number of bytes that the next |
I honestly don't know a lot about these subjects, but if all our IOs are non-blocking by default, why do we need a |
Maybe @waj could comment more on this... |
It quickly becomes important in TUI applications when reading keypresses, you may want to redraw continuously while no key is pressed, so not block on waiting for the next keypress, but also have precise control over when to read the next keypress. |
Maybe it's about configuring something in IO::FileDescriptor to return the read bytes instead of switching to another fiber? The check should be done here: https://github.com/crystal-lang/crystal/blob/master/src/io/file_descriptor.cr#L216-L234 Instead of calling How can we test this, if we want to support such feature? |
Reading from an empty pipe should work I guess. |
Do IO#read methods wait for all requested bytes or return with any available data? The current implementation varies in behavior depending the number of bytes requested. What is the intended behavior?
Completely missing is read_partial functionality - a method that returns any available bytes <= the requested size.
The text was updated successfully, but these errors were encountered: