https://redmine.ruby-lang.org/https://redmine.ruby-lang.org/favicon.ico?17113305112012-11-04T01:11:21ZRuby Issue Tracking SystemRuby master - Bug #7269: Refinement doesn't work if using locate after methodhttps://redmine.ruby-lang.org/issues/7269?journal_id=322972012-11-04T01:11:21Zheadius (Charles Nutter)headius@headius.com
<ul></ul><p>I don't like the idea that using should affect methods already defined. At this point I view using similar to private/protected/etc, which also do not affect methods defined before you call them.</p> Ruby master - Bug #7269: Refinement doesn't work if using locate after methodhttps://redmine.ruby-lang.org/issues/7269?journal_id=322982012-11-04T01:53:17Zko1 (Koichi Sasada)
<ul></ul><p>(2012/11/03 10:11), headius (Charles Nutter) wrote:</p>
<blockquote>
<p>I don't like the idea that using should affect methods already defined. At this point I view using similar to private/protected/etc, which also do not affect methods defined before you call them.</p>
</blockquote>
<p>I feel that <code>using' is similar to </code>include' and <code>prepend' rather than </code>public' and `private'.</p>
<p>--<br>
// SASADA Koichi at atdot dot net</p> Ruby master - Bug #7269: Refinement doesn't work if using locate after methodhttps://redmine.ruby-lang.org/issues/7269?journal_id=323002012-11-04T01:53:18Zko1 (Koichi Sasada)
<ul></ul><p>(2012/11/03 10:36), SASADA Koichi wrote:</p>
<blockquote>
<p>(2012/11/03 10:11), headius (Charles Nutter) wrote:</p>
<blockquote>
<p>I don't like the idea that using should affect methods already defined. At this point I view using similar to private/protected/etc, which also do not affect methods defined before you call them.</p>
</blockquote>
<p>I feel that <code>using' is similar to </code>include' and <code>prepend' rather than </code>public' and `private'.</p>
</blockquote>
<p>The following code (C_User2#x) affect refinement `after' defining<br>
method. Is that intentional?</p>
<h3></h3>
<p>class C<br>
def foo<br>
p :C_foo<br>
end<br>
end</p>
<p>module RefineC<br>
refine C do<br>
def foo<br>
p :RefineC_foo<br>
super<br>
end<br>
end<br>
end</p>
<p>class C_User<br>
using RefineC<br>
def x<br>
C.new.foo<br>
end<br>
end</p>
<p>class C_User2<br>
def x<br>
self.class.send(:using, RefineC)<br>
C.new.foo<br>
end<br>
end</p>
<p>puts "C.new.foo"<br>
C.new.foo</p>
<p>puts "C_User.new.x"<br>
C_User.new.x</p>
<p>puts "C_User2.new.x"<br>
C_User2.new.x</p>
<p>#=><br>
C.new.foo<br>
:C_foo<br>
C_User.new.x<br>
:RefineC_foo<br>
:C_foo<br>
C_User2.new.x<br>
:RefineC_foo<br>
:C_foo</p>
<p>--<br>
// SASADA Koichi at atdot dot net</p> Ruby master - Bug #7269: Refinement doesn't work if using locate after methodhttps://redmine.ruby-lang.org/issues/7269?journal_id=323012012-11-04T01:53:18Zko1 (Koichi Sasada)
<ul></ul><p>(2012/11/03 10:42), SASADA Koichi wrote:</p>
<blockquote>
<h3></h3>
<p>class C<br>
def foo<br>
p :C_foo<br>
end<br>
end</p>
<p>module RefineC<br>
refine C do<br>
def foo<br>
p :RefineC_foo<br>
super<br>
end<br>
end<br>
end</p>
<p>class C_User<br>
using RefineC<br>
def x<br>
C.new.foo<br>
end<br>
end</p>
<p>class C_User2<br>
def x<br>
self.class.send(:using, RefineC)<br>
C.new.foo<br>
end<br>
end</p>
<p>puts "C.new.foo"<br>
C.new.foo</p>
<p>puts "C_User.new.x"<br>
C_User.new.x</p>
<p>puts "C_User2.new.x"<br>
C_User2.new.x</p>
<p>#=><br>
C.new.foo<br>
:C_foo<br>
C_User.new.x<br>
:RefineC_foo<br>
:C_foo<br>
C_User2.new.x<br>
:RefineC_foo<br>
:C_foo</p>
</blockquote>
<a name="is-that-corner-case-"></a>
<h1 >is that corner case? :)<a href="#is-that-corner-case-" class="wiki-anchor">¶</a></h1>
<p>class C_User2<br>
def x<br>
2.times{<br>
C.new.foo<br>
self.class.send(:using, RefineC)<br>
}<br>
end<br>
end</p>
<p>--<br>
// SASADA Koichi at atdot dot net</p> Ruby master - Bug #7269: Refinement doesn't work if using locate after methodhttps://redmine.ruby-lang.org/issues/7269?journal_id=323032012-11-04T02:23:25Zheadius (Charles Nutter)headius@headius.com
<ul></ul><p>On Sat, Nov 3, 2012 at 10:45 AM, SASADA Koichi <a href="mailto:ko1@atdot.net" class="email">ko1@atdot.net</a> wrote:</p>
<blockquote>
<a name="is-that-corner-case-"></a>
<h1 >is that corner case? :)<a href="#is-that-corner-case-" class="wiki-anchor">¶</a></h1>
<p>class C_User2<br>
def x<br>
2.times{<br>
C.new.foo<br>
self.class.send(:using, RefineC)<br>
}<br>
end<br>
end</p>
</blockquote>
<p>I commented on the other bug about how refinements need to be temporal<br>
to limit their impact (implementation-wise), but there are obvious<br>
flaws in making them temporal too. Your example above shows how<br>
ordering can change what method will be called. My example was using<br>
calls that happen up-hierarchy in different files.</p>
<p>Even if we ignore implementation/performance concerns (and there are<br>
lots of them), there are many behavioral problems like this with<br>
refinements.</p> Ruby master - Bug #7269: Refinement doesn't work if using locate after methodhttps://redmine.ruby-lang.org/issues/7269?journal_id=323612012-11-05T12:16:09Zshugo (Shugo Maeda)
<ul></ul><p>headius (Charles Nutter) wrote:</p>
<blockquote>
<p>I commented on the other bug about how refinements need to be temporal<br>
to limit their impact (implementation-wise), but there are obvious<br>
flaws in making them temporal too. Your example above shows how<br>
ordering can change what method will be called. My example was using<br>
calls that happen up-hierarchy in different files.</p>
<p>Even if we ignore implementation/performance concerns (and there are<br>
lots of them), there are many behavioral problems like this with<br>
refinements.</p>
</blockquote>
<p>I've started to wonder if it's better to limit refinements based on modules instead of lexical scopes.</p>
<p>In the current implementation a cref has a table for activated refinements, but in module-based refinements<br>
a module linked from the cref have the table.<br>
Furthermore, in the current implementation the table is shared and copied-on-write by nested crefs, but it may<br>
be better to separate them and search refinements in outer modules when a method is not found in the table of the current module.</p>
<p>For example,</p>
<p>modue Foo<br>
using X</p>
<a name="Foos-table-has-refinements-in-X"></a>
<h1 >Foo's table has refinements in X.<a href="#Foos-table-has-refinements-in-X" class="wiki-anchor">¶</a></h1>
<p>module Bar<br>
using Y<br>
# Bar's table has refinements in Y, not X.</p>
<pre><code>C.new.foo # First, Bar's table is searched, then Foo's table is searched.
</code></pre>
<p>end<br>
end</p>
<p>In module-based refinements, toplevel using should affects not only the current file, but global.</p> Ruby master - Bug #7269: Refinement doesn't work if using locate after methodhttps://redmine.ruby-lang.org/issues/7269?journal_id=323622012-11-05T13:10:48Zmatz (Yukihiro Matsumoto)matz@ruby.or.jp
<ul></ul><p>OK, I understand the behavior. What are pros and cons of module based refinement?</p>
<p>Matz.</p> Ruby master - Bug #7269: Refinement doesn't work if using locate after methodhttps://redmine.ruby-lang.org/issues/7269?journal_id=323672012-11-05T13:42:52Zheadius (Charles Nutter)headius@headius.com
<ul></ul><p>Making refinements <em>less</em> lexical seems like the wrong direction to me. It means all calls everywhere have to check for refinements all the time, similar to the module_eval problem.</p>
<p>In the following code:</p>
<p>a.rb:</p>
<p>module Foo<br>
def self.go<br>
C.new.foo<br>
end<br>
end</p>
<p>b.rb:</p>
<p>module Foo<br>
using X<br>
end</p>
<p>I assume that regardless of the order of loading these two files, calling the "go" method would require searching the refinements table of Foo, correct? That seems pretty clearly to indicate that module-based refinements require all call sites everywhere to check for refinements every time.</p> Ruby master - Bug #7269: Refinement doesn't work if using locate after methodhttps://redmine.ruby-lang.org/issues/7269?journal_id=323682012-11-05T13:49:19Zheadius (Charles Nutter)headius@headius.com
<ul></ul><p>I should also mention that if we can't tell ahead of time that a call site has to search refinements, it means all calls everywhere will have to have cref available. In JRuby, this could easily be a crippling blow to performance, and in MRI it would make it impossible to eliminate Ruby call frames (or eliminate cref management) ever in the future (which I'm sure ko1 would like to be able to do).</p>
<p>Currently JRuby only needs the cref to be available if there's a closure, binding-related call, or constant lookup. We'd now have to make it available 100% of the time.</p>
<p>It also means that you will never again be able to look at a piece of code and know if refinements will affect it. Refinements would become one of the most confusing features in Ruby.</p>
<p>After talking with Yehuda a bit, I am more and more of the opinion that "using" should only affect call sites lexically in the same scope as (or a child scope of) the "using" call, and only call sites that appear after the "using" call. This would mean having to use "using" in every file where you want refinements active, but it would make it very where refinements are active both to the programmer and to the VM.</p> Ruby master - Bug #7269: Refinement doesn't work if using locate after methodhttps://redmine.ruby-lang.org/issues/7269?journal_id=323732012-11-05T14:49:09Zshugo (Shugo Maeda)
<ul></ul><p>matz (Yukihiro Matsumoto) wrote:</p>
<blockquote>
<p>OK, I understand the behavior. What are pros and cons of module based refinement?</p>
</blockquote>
<p>pros:</p>
<ul>
<li>not affected by the order of loading/using</li>
<li>consistent with module_eval and behavior when a module is reopened (Bug <a class="issue tracker-1 status-5 priority-4 priority-default closed" title="Bug: Refinement doesn't seem lexical (Closed)" href="https://redmine.ruby-lang.org/issues/7271">#7271</a>)</li>
</ul>
<p>cons:</p>
<ul>
<li>might be hard to implement efficiently
<ul>
<li>especially super when refinements are cascaded might be hard to implement</li>
</ul>
</li>
</ul> Ruby master - Bug #7269: Refinement doesn't work if using locate after methodhttps://redmine.ruby-lang.org/issues/7269?journal_id=346892012-12-13T14:16:23Zshugo (Shugo Maeda)
<ul><li><strong>Status</strong> changed from <i>Open</i> to <i>Closed</i></li></ul><p>Module#using is removed, so I close this ticket.</p>
<p>See <a href="https://bugs.ruby-lang.org/projects/ruby-trunk/wiki/RefinementsSpec" class="external">https://bugs.ruby-lang.org/projects/ruby-trunk/wiki/RefinementsSpec</a> for scoping of main.using.</p>