Feature #18357
openProposal: stop raising when block passed to IO#each_* closes the IO
Description
As of #17661, all of the enumeration methods on IO
—e.g. each_line
, each_byte
, each_codepoint
—raise IOError
when the given block closes the IO
. For example, the following code raises an IOError
if the peer sends a line containing only quit
:
socket.each_line do |line|
if line.casecmp?("quit\n")
socket.puts "Goodbye"
socket.close
end
end
In this example, it’s trivial to break
after closing the client socket. However, in real code, it’s likely that the command-handling code will be further away from the loop and unable to break
out of the loop. Either the command-handling method and all intervening methods need to pass an indication of whether to keep reading back down the stack, or the block needs to include an explicit break if io.closed?
.
In my experience, when I close an IO
within a read loop, I intend to immediately stop reading as well. It would be more agreeable if each_line
et al. simply stopped reading when the IO
is closed in the block instead of raising IOError
.
I recognize this may be considered a breaking change. The patch for #17661 was backported to 3.0, and each_line
has behaved this way for longer. This may be workable as an option to the enumeration methods, but I’m not sure an option is worth its weight compared to explicit break if io.closed?
. I’m mostly asking for a decision on whether the implicit behavior is worth changing for convenience and developer happiness (and aware the answer may be no).
I’ve attached a patch containing a sample implementation for IO#each_line
and updated specs. I believe this change can be implemented similarly for all other enumeration methods.
Files
No data to display