https://bugs.ruby-lang.org/https://bugs.ruby-lang.org/favicon.ico?17113305112020-12-23T00:40:02ZRuby Issue Tracking SystemRuby master - Bug #17428: Method#inspect bad output for class methodshttps://bugs.ruby-lang.org/issues/17428?journal_id=894262020-12-23T00:40:02Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<ul></ul><p>Correct output would be:</p>
<pre><code>#<Method: #<Class:String>(Module)#prepend(*)>
# or even better imo to reuse the '.' notation here:
#<Method: String(Module).prepend(*)>
</code></pre> Ruby master - Bug #17428: Method#inspect bad output for class methodshttps://bugs.ruby-lang.org/issues/17428?journal_id=894322020-12-23T05:41:21Zjeremyevans0 (Jeremy Evans)merch-redmine@jeremyevans.net
<ul></ul><p>I submitted a pull request to fix this issue: <a href="https://github.com/ruby/ruby/pull/3984" class="external">https://github.com/ruby/ruby/pull/3984</a></p> Ruby master - Bug #17428: Method#inspect bad output for class methodshttps://bugs.ruby-lang.org/issues/17428?journal_id=894372020-12-23T11:07:11ZEregon (Benoit Daloze)
<ul></ul><p>FWIW, current output on TruffleRuby is:</p>
<pre><code>ruby -e 'p String.method(:prepend)'
#<Method: Class(Module)#prepend(*modules) <internal:core> core/module.rb:92>
</code></pre>
<p>Probably it should show <code>#<Class:String></code> instead of <code>Class</code> though.</p>
<pre><code>#<Method: String(Module).prepend(*)>
</code></pre>
<p>doesn't seem correct, prepend is not a class method of <code>Module</code>, it's an instance method.</p> Ruby master - Bug #17428: Method#inspect bad output for class methodshttps://bugs.ruby-lang.org/issues/17428?journal_id=894382020-12-23T11:23:24ZEregon (Benoit Daloze)
<ul></ul><p>With a trivial fix (using the actual class/rb_class_of(), not just <code>.class</code>), I get this in TruffleRuby, which I think is the correct output:</p>
<pre><code>$ ruby -e 'p String.method(:prepend)'
#<Method: #<Class:String>(Module)#prepend(*modules) <internal:core> core/module.rb:92>
$ ruby -e 'p String.method(:prepend).unbind'
#<UnboundMethod: #<Class:String>(Module)#prepend(*modules) <internal:core> core/module.rb:92>
</code></pre>
<p>You'll notice it's quite close to MRI's output for an UnboundMethod:</p>
<pre><code># #<Class:Object> instead of #<Class:String> is the bug, the rest is fine
$ ruby-master -e 'p String.method(:prepend).unbind'
#<UnboundMethod: #<Class:Object>(Module)#prepend(*)>
$ ruby-2.7.2 -e 'p String.method(:prepend).unbind'
#<UnboundMethod: #<Class:String>#prepend(*)>
</code></pre>
<p>The actual logic for Method#inspect and and UnboundMethod#inspect should be similar, and I think the logic in TruffleRuby is correct and makes the most sense:<br>
<a href="https://github.com/oracle/truffleruby/blob/0aeb60024d025e3d3d836bd08ff89479d4292bb7/src/main/ruby/truffleruby/core/truffle/method_operations.rb#L37-L42" class="external">https://github.com/oracle/truffleruby/blob/0aeb60024d025e3d3d836bd08ff89479d4292bb7/src/main/ruby/truffleruby/core/truffle/method_operations.rb#L37-L42</a></p>
<p>The crucial part for this case: only use the <code>.</code> notation if the owner of the method (Method#owner) is a singleton class, <em>not</em> if the receiver has a singleton class.</p>
<pre><code># All Rubies agree on:
$ ruby -e 'p String.method(:prepend).owner.singleton_class?'
false
</code></pre> Ruby master - Bug #17428: Method#inspect bad output for class methodshttps://bugs.ruby-lang.org/issues/17428?journal_id=894402020-12-23T15:31:26Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<ul></ul><p>Eregon (Benoit Daloze) wrote in <a href="#note-3">#note-3</a>:</p>
<blockquote>
<pre><code>#<Method: String(Module).prepend(*)>
</code></pre>
<p>doesn't seem correct, prepend is not a class method of <code>Module</code>, it's an instance method.</p>
</blockquote>
<p>When <code>(X)</code> appears, it means <code>actually an instance method of X</code>, even in the case where <code>.</code> appears later. So not incorrect, but I agree it might be confusing. How about this other possibility?</p>
<pre><code>#<Method: String.(Module#)prepend(*)>
</code></pre> Ruby master - Bug #17428: Method#inspect bad output for class methodshttps://bugs.ruby-lang.org/issues/17428?journal_id=894412020-12-23T15:37:27ZEregon (Benoit Daloze)
<ul></ul><p>For me, <code>Foo.bar</code> immediately means "singleton method of Foo", which is not the case here.<br>
So I think we should only use the <code>.</code> form when Method#owner is a singleton class.</p>
<p>I recommend simplicity and consistency (between object singleton classes and metaclasses).<br>
The output of Method#inspect has been confusing in the past and sometimes wrong, the way to solve it IMHO is a simple rule and a consistent output.<br>
So I'm against making it more complicated / more edge cases.</p> Ruby master - Bug #17428: Method#inspect bad output for class methodshttps://bugs.ruby-lang.org/issues/17428?journal_id=894452020-12-23T15:46:02Zjeremyevans0 (Jeremy Evans)merch-redmine@jeremyevans.net
<ul></ul><p>Using <code>#<Class:String>(Module)#</code> instead of <code>String(Module).</code> is a trivial change to make, and I have no preference between the two. <code>String.(Module#)</code> is a significantly more invasive change and I don't think we should go that route. It would be great to get feedback from other committers regarding this today if we want this fix to make 3.0.</p> Ruby master - Bug #17428: Method#inspect bad output for class methodshttps://bugs.ruby-lang.org/issues/17428?journal_id=894482020-12-23T16:19:10Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<ul><li><strong>Assignee</strong> changed from <i>jeremyevans0 (Jeremy Evans)</i> to <i>matz (Yukihiro Matsumoto)</i></li></ul><p>jeremyevans0 (Jeremy Evans) wrote in <a href="#note-7">#note-7</a>:</p>
<blockquote>
<p><code>String.(Module#)</code> is a significantly more invasive change</p>
</blockquote>
<p>I prefer to decide "what do we want" than "what is easier". Change was actually a few lines changes for that version: <a href="https://github.com/ruby/ruby/pull/3985" class="external">https://github.com/ruby/ruby/pull/3985</a></p>
<p>Matz, which do you prefer:</p>
<pre><code>$ ruby -e 'p String.method(:prepend)'
#<Method: String(Module).prepend(*modules)...>
#<Method: String.(Module#)prepend(*modules)...>
#<Method: #<Class:String>(Module)#prepend(*modules)...>
</code></pre> Ruby master - Bug #17428: Method#inspect bad output for class methodshttps://bugs.ruby-lang.org/issues/17428?journal_id=894892020-12-24T03:30:01Zjeremyevans (Jeremy Evans)code@jeremyevans.net
<ul><li><strong>Status</strong> changed from <i>Open</i> to <i>Closed</i></li></ul><p>Applied in changeset <a class="changeset" title="Fix class of method in Method#inspect for singleton classes of classes Previously, due to a chan..." href="https://bugs.ruby-lang.org/projects/ruby-master/repository/git/revisions/1e215a66d26d56befab4fbb72e1d953879411955">git|1e215a66d26d56befab4fbb72e1d953879411955</a>.</p>
<hr>
<p>Fix class of method in Method#inspect for singleton classes of classes</p>
<p>Previously, due to a change to fix bug 15608, Method#inspect output<br>
changed for class methods:</p>
<p>Ruby 2.7<br>
"#<Method: String.prepend(*)>"</p>
<p>Before change:<br>
"#<Method: #<a href="Class:Object" class="external">Class:Object</a>(Module)#prepend(*)>"</p>
<p>This is wrong because the Method object was created from String and<br>
not Object. This is because the fix for bug 15608 assumed it was<br>
being called on the singleton class of a instance, and would skip<br>
the first singleton class until it got to the class itself. For<br>
class methods, this results in always using the superclass. Fix<br>
behavior to not skip until the superclass if the singleton class<br>
is the singleton class of a module or class.</p>
<p>After change:<br>
"#<Method: #<a href="Class:Object" class="external">Class:Object</a>(Module)#prepend(*)>"</p>
<p>Fixes [Bug <a class="issue tracker-1 status-5 priority-4 priority-default closed" title="Bug: Method#inspect bad output for class methods (Closed)" href="https://bugs.ruby-lang.org/issues/17428">#17428</a>]</p> Ruby master - Bug #17428: Method#inspect bad output for class methodshttps://bugs.ruby-lang.org/issues/17428?journal_id=895102020-12-24T11:06:15ZEregon (Benoit Daloze)
<ul></ul><p>marcandre (Marc-Andre Lafortune) wrote in <a href="#note-8">#note-8</a>:</p>
<blockquote>
<p>I prefer to decide "what do we want" than "what is easier".</p>
</blockquote>
<p>I'm not matz, but what I want for Method#inspect is consistency and a clear rule for formatting.<br>
(<a href="https://github.com/oracle/truffleruby/blob/0aeb60024d025e3d3d836bd08ff89479d4292bb7/src/main/ruby/truffleruby/core/truffle/method_operations.rb#L37-L42" class="external">https://github.com/oracle/truffleruby/blob/0aeb60024d025e3d3d836bd08ff89479d4292bb7/src/main/ruby/truffleruby/core/truffle/method_operations.rb#L37-L42</a> seems a good one)<br>
IMHO more special cases just lead to bugs like this, confusion as before <a class="issue tracker-1 status-5 priority-4 priority-default closed" title="Bug: What should be the correct output for Method#inspect with singleton methods? (Closed)" href="https://bugs.ruby-lang.org/issues/15608">#15608</a>, or harder-to-understand output.</p>
<p>Method#inspect doesn't need to be "as nice as possible", I think it needs to be "easy to understand and consistent to help comparison and avoid ambiguity".</p>
<p>I think this is a good example why the behavior of current master with Jeremy's fix is better:</p>
<pre><code>$ ruby -e 'p Module.method(:prepend)'
2.7.2, confusing, prepend is not a singleton method
#<Method: Module.prepend(*)>
CRuby master with Jeremy's fix (same on TruffleRuby): clear, simple, consistent
#<Method: #<Class:Module>(Module)#prepend(*)>
the proposals above, IMHO both are unclear and confusing:
#<Method: Module(Module).prepend(*)>
#<Method: Module.(Module#)prepend(*)>
</code></pre> Ruby master - Bug #17428: Method#inspect bad output for class methodshttps://bugs.ruby-lang.org/issues/17428?journal_id=895142020-12-24T15:58:47Zjeremyevans0 (Jeremy Evans)merch-redmine@jeremyevans.net
<ul></ul><p>After thinking about this more, I would prefer :</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Module</span><span class="p">.</span><span class="nf">method</span><span class="p">(</span><span class="ss">:prepend</span><span class="p">)</span>
<span class="c1"># => #<Method: Module.prepend(Module#prepend)(*)></span>
</code></pre>
<p>Basically, show the method based on the receiver, then, if it is different, the method based on the owner. I think this is conceptually simpler. The only issue it will result in the method name showing up twice even if the method has not been aliased.</p>
<p>Additional examples:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">A</span>
<span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">b</span><span class="p">;</span> <span class="k">end</span>
<span class="k">end</span>
<span class="k">class</span> <span class="nc">C</span> <span class="o"><</span> <span class="no">A</span><span class="p">;</span>
<span class="k">end</span>
<span class="no">C</span><span class="p">.</span><span class="nf">method</span><span class="p">(</span><span class="ss">:b</span><span class="p">)</span>
<span class="c1"># => #<Method: C.b(A.b)(*)></span>
<span class="k">module</span> <span class="nn">M</span>
<span class="k">def</span> <span class="nf">b</span><span class="p">;</span> <span class="k">end</span>
<span class="k">end</span>
<span class="no">C</span><span class="p">.</span><span class="nf">extend</span> <span class="no">M</span>
<span class="no">C</span><span class="p">.</span><span class="nf">method</span><span class="p">(</span><span class="ss">:b</span><span class="p">)</span>
<span class="c1"># => #<Method: C.b(M#b)(*)></span>
<span class="no">String</span><span class="p">.</span><span class="nf">new</span><span class="p">.</span><span class="nf">method</span><span class="p">(</span><span class="ss">:to_s</span><span class="p">)</span>
<span class="c1"># => #<Method: String#to_s(*)></span>
<span class="k">class</span> <span class="nc">S</span> <span class="o"><</span> <span class="no">String</span>
<span class="k">end</span>
<span class="no">S</span><span class="p">.</span><span class="nf">new</span><span class="p">.</span><span class="nf">method</span><span class="p">(</span><span class="ss">:to_s</span><span class="p">)</span>
<span class="c1"># => #<Method: S#to_s(String#to_s)(*)></span>
</code></pre> Ruby master - Bug #17428: Method#inspect bad output for class methodshttps://bugs.ruby-lang.org/issues/17428?journal_id=895172020-12-25T00:53:08ZEregon (Benoit Daloze)
<ul><li><strong>Backport</strong> changed from <i>2.5: UNKNOWN, 2.6: UNKNOWN, 2.7: UNKNOWN</i> to <i>2.5: UNKNOWN, 2.6: UNKNOWN, 2.7: REQUIRED</i></li></ul><p>Agreed that looks nice, but what should be shown from the example in <a class="issue tracker-1 status-5 priority-4 priority-default closed" title="Bug: What should be the correct output for Method#inspect with singleton methods? (Closed)" href="https://bugs.ruby-lang.org/issues/15608">#15608</a>?</p>
<pre><code>p obj.method(:foo)
#<Method: C#foo>
vs
#<Method: #<C:0x000055668ebef268>.foo(C#foo)>
</code></pre>
<p>based on whether the instance has a singleton class doesn't seem ideal.</p>
<p>I wonder if always using the <code>#</code> notation wouldn't be simpler and more consistent (we'd always see the module in which the method is defined).<br>
If it's a singleton class method, we might as well show the singleton class.</p>
<p>I think a new feature to discuss it would be best, the bug that <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/182">@marcandre (Marc-Andre Lafortune)</a> found has been fixed now.</p> Ruby master - Bug #17428: Method#inspect bad output for class methodshttps://bugs.ruby-lang.org/issues/17428?journal_id=910172021-03-20T06:52:08Znagachika (Tomoyuki Chikanaga)nagachika00@gmail.com
<ul></ul><p>MEMO: Though there should be some preceding changesets, I gave up to find it for the time being.</p>