-
-
Notifications
You must be signed in to change notification settings - Fork 62
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
Unclear semantics of write() in WritableStreamInterface #79
Comments
Thanks for raising this very interesting issue 👍 The documentation has only recently been added via #72, so I very much appreciate this kind of feedback, which I hope we can use to make this documentation more obvious in the future 👍
I agree that this isn't perfectly clear from the docs, but here's how this works for the The I hope this helps 👍
This is related to #37, so I hope you agree we keep this separated? |
Thank you for the response. It helped me to understand how this function works. Maybe we should change the docs so it would say something like this:
And there still is a question about writing to a closed stream. Currently it returns And after reading README again I see another thing that is not clear:
It is unclear here, if there was an error on the stream but it has not been not closed, are the data lost? Will the stream try to write them again? Will it discard the chunk of data that caused the error and start writing other data? It would be better if there were some guarantees, for example, either all data are successfully written or the stream is closed and an error is reported. Regarding writing to a read-only stream, I agree, that is a separate issue, I just didn't know it exists. |
With all this being said, keep in mind that this documentation applies to the generic
I think you're on to something here and I would love to review this more in-depth 👍 May I ask you to file this as a PR so we can look into getting this in? 👍
The problem with an async code flow is that state isn't entirely under user control and relies on external factors, such as the remote side closing the connection, which can basically happen any time. I'm not sure how adding exceptions here would exactly be helpful? The
I agree that it's not exactly clear here, so I'm all for improving this text. However, I'm not sure this is something we can guarantee, given the different implementations this interface can have and has. The most common implementations (TCP/IP etc.) will close the stream and discard all data. Any suggestions here? |
Yes, I will try to make a PR with changes to README later, to make the documentation more clear, but I still have some questions and more ideas. Let me explain why I created this issue. Let's say I want to use streams in a project (actually I already use them). For example, I write a function that asynchronously writes data to a stream passed as an argument. I understand that any I/O operations can fail but want my code to do the best it can. Here is what I want from my code:
It would be nice if the documentation explained how to use the functions so that no data is lost, no event is missed. And maybe provide some guarantees. Because without that it is difficult to write a code that works correctly. I would have to look into the code for every implementation of a stream to check that it works as I assume. I think it might even be better to add small code snippets showing an example of such code that is 100% correct. I will try to write such example: function writeSomethingToStream(WritableStreamInterface $stream)
{
$stream->on('error', function (\Exception $e) {
// Nothing can be done, so terminate the program
echo "Operation failed\n";
throw $e;
});
$stream->on('end', function () {
echo "Operation completed successfully\n";
});
// Now we can write data to the stream
// Here I write them synchronously for simplicity
$stream->write('1');
$stream->write('2');
$stream->write('3');
// Close stream
$stream->end();
} I wonder, is this code correct? I think it might fail if we call And the Also I have a question about I have looked at the code for (You might notice that I really care much about error reporting. That is because hiding error messages makes the debugging much more difficult so I don't want to miss any). And I'd like to ask a question about
The easiest thing to do would be to require that any error on the stream
I agree that it is complicated. On the one side we don't know when error happens, but on the other side ignoring |
The documentation has only recently been added via #72, in an attempt to provide a consistent documentation for the existing behavior. I think you're on to something here and support that we may want to look into providing some stricter semantics here. This ticket here is quite lengthy and I don't suppose many will follow through, so may I ask you to file this as an RFC ticket or perhaps even better as a PR? 👍
I agree that adding examples here would help getting people into this new code flow and the expected events more easily. Can you file a (separate) PR that adds relevant examples? 👍
I'm not sure I understand what you're suggesting what we should do instead. IMHO we should document this as expected behavior and explicitly link to the |
I have read the description of WritableStreamInterface here: https://github.com/reactphp/stream#write and it looks very unclear. I don't really understand what is the meaning of return value (
true
/false
) forwrite()
and how I should use it to make sure that all data are written, so I am not writing into closed or broken stream.Let me quote the docs:
This sentences are contradicting: the first one says that
write()
must return true if the data were saved into a buffer but the second one says thatwrite()
can return false in this case. Should I checkwrite()
's return value? Should I consider returningfalse
an error?Another thing I didn't understand is why write() to a non-writable or closed stream (which is programmer's mistake) is silently ignored instead of throwing an exception. Doesn't this make finding such mistake harder?
Also, I didn't understand how the code is separated between
Stream
andBuffer
classes. They both hold a reference to the underlying stream, they both emit events, they both havewritable
property... would not it be easier to make it a single class?Also, the
isWritable()
method doesn't know anything about the underlying stream:As I understand,
isWritable()
only checks whether the stream has not been closed so maybe a better name would beisOpened()
?The text was updated successfully, but these errors were encountered: