From: "akr (Akira Tanaka) via ruby-core" Date: 2023-06-09T09:47:32+00:00 Subject: [ruby-core:113846] [Ruby master Feature#19712] IO#reopen removes singleton class Issue #19712 has been updated by akr (Akira Tanaka). I proposed adding a keyword argument as `io1.reopen(io2, retain_class:true)` at the meeting. The keyword argument `retain_class:true` disables changing the class. That means `io1.reopen(io2, retain_class:true)` just do `dup2(io2.fileno, io1.fileno)`. This extension is compatible, as far as `retain_class:false` is the default. If we don't need to use io2-specific methods for io1, we don't need to change the class of io1, and `retain_class:true` should work fine. (Singleton methods of io1 will retain.) matz said it is not worth enough over his concern about possible incompatibility. As far as I understand his concern, he is afraid that IO methods may not work for file descriptors for sockets on Windows. Although I'm not a Windows expert, I guess IO methods work for sockets. At least `read` and `write` methods are inherited to TCPSocket and they work fine now. ``` % ruby -rsocket -e 'p TCPSocket.method(:read), TCPSocket.method(:write)' # # ``` ---------------------------------------- Feature #19712: IO#reopen removes singleton class https://bugs.ruby-lang.org/issues/19712#change-103495 * Author: itarato (Peter Arato) * Status: Open * Priority: Normal ---------------------------------------- The documentation states: > This may dynamically change the actual class of this stream. As well `#reopen` removes the singleton class, even when the logical class is the same. This can be surprising at times. An example: ``` ruby io = File.open(__FILE__) io.define_singleton_method(:foo) {} io.reopen(File.open(__FILE__)) io.foo # `
': undefined method `foo' for # (NoMethodError) ``` An example where this was an issue: https://github.com/oracle/truffleruby/pull/3088 Tl;dr: a popular gem was enhancing the singleton class of STDOUT, while Rails/ActiveSupport was executing an `IO#reopen` - invalidating the changes by the gem. While it's hard to trivially solve this with keeping the intended functionality, could it be considered to make edge cases more visible? Examples: - `IO#reopen` issues a warning message when the receiver's singleton class has been updated (but keep removing it as of current state) - `IO#reopen` is limited on instances with a default singleton class, and issues an error when called on an instance with an updated singleton class - make `IO#reopen` carry over the singleton class *only* if the recipient and argument's class are the same, and yield an error otherwise (different classes) These are just ideas. I'm more looking for feedback from the core devs at this point. Thanks in advance! -- https://bugs.ruby-lang.org/ ______________________________________________ ruby-core mailing list -- ruby-core@ml.ruby-lang.org To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org ruby-core info -- https://ml.ruby-lang.org/mailman3/postorius/lists/ruby-core.ml.ruby-lang.org/