https://bugs.ruby-lang.org/https://bugs.ruby-lang.org/favicon.ico?17113305112015-02-03T00:31:58ZRuby Issue Tracking SystemRuby master - Bug #10818: Extrange behaviour when apliying a refinement inside evalhttps://bugs.ruby-lang.org/issues/10818?journal_id=513472015-02-03T00:31:58Zpabloh (Pablo Herrero)pablodherrero@gmail.com
<ul></ul><p>I really wish I could fix the typos at the title...</p> Ruby master - Bug #10818: Extrange behaviour when apliying a refinement inside evalhttps://bugs.ruby-lang.org/issues/10818?journal_id=513592015-02-03T07:27:26Zhanachin (Seiei Miyagi)hanachin@gmail.com
<ul></ul><p>The <code>Kernel.#eval</code> behaves like:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="nb">eval</span><span class="p">(</span><span class="s1">'a = 42'</span><span class="p">)</span>
<span class="nb">eval</span><span class="p">(</span><span class="s1">'p a'</span><span class="p">)</span>
<span class="c1"># bar.rb:2:in `eval': undefined local variable or method `a' for main:Object (NameError)</span>
<span class="c1"># from bar.rb:2:in `eval'</span>
<span class="c1"># from bar.rb:2:in `<main>'</span>
</code></pre>
<p>But <code>Binding#eval</code> behaves like:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">b</span> <span class="o">=</span> <span class="nb">binding</span>
<span class="n">b</span><span class="p">.</span><span class="nf">eval</span><span class="p">(</span><span class="s2">"a = 42"</span><span class="p">)</span>
<span class="n">b</span><span class="p">.</span><span class="nf">eval</span><span class="p">(</span><span class="s2">"p a"</span><span class="p">)</span>
<span class="c1"># => 42</span>
</code></pre>
<p>So, I expect following code works fine, but it raises <code>NoMethodError</code> in ruby 2.1.5, 2.2.0</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">Foo</span><span class="p">;</span> <span class="k">end</span>
<span class="k">module</span> <span class="nn">M</span>
<span class="n">refine</span><span class="p">(</span><span class="no">Foo</span><span class="p">)</span> <span class="k">do</span>
<span class="k">def</span> <span class="nf">bar</span>
<span class="mi">42</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">b</span> <span class="o">=</span> <span class="nb">binding</span>
<span class="n">b</span><span class="p">.</span><span class="nf">eval</span><span class="p">(</span><span class="s1">'using M'</span><span class="p">)</span>
<span class="nb">puts</span> <span class="n">b</span><span class="p">.</span><span class="nf">eval</span><span class="p">(</span><span class="s1">'Foo.new.bar'</span><span class="p">)</span>
<span class="c1"># expected:</span>
<span class="c1"># 42</span>
<span class="c1">#</span>
<span class="c1"># actual 2.0.0:</span>
<span class="c1"># refinement.rb:4: warning: Refinements are experimental, and the behavior may change in future versions of Ruby!</span>
<span class="c1"># 42</span>
<span class="c1">#</span>
<span class="c1"># actual 2.1.5:</span>
<span class="c1"># refinement.rb:11:in `<main>': undefined method `bar' for #<Foo:0x007fe3040fd568> (NoMethodError)</span>
<span class="c1"># from refinement.rb:13:in `eval'</span>
<span class="c1"># from refinement.rb:13:in `<main>'</span>
<span class="c1">#</span>
<span class="c1"># actual 2.2.0</span>
<span class="c1"># refinement.rb:11:in `<main>': undefined method `bar' for #<Foo:0x007f9fba04e488> (NoMethodError)</span>
<span class="c1"># from refinement.rb:13:in `eval'</span>
<span class="c1"># from refinement.rb:13:in `<main>'</span>
</code></pre> Ruby master - Bug #10818: Extrange behaviour when apliying a refinement inside evalhttps://bugs.ruby-lang.org/issues/10818?journal_id=513602015-02-03T07:33:45Zhanachin (Seiei Miyagi)hanachin@gmail.com
<ul></ul><p>When call <code>Kernel.#eval</code> with <code>binding</code> returns same result.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">Foo</span><span class="p">;</span> <span class="k">end</span>
<span class="k">module</span> <span class="nn">M</span>
<span class="n">refine</span><span class="p">(</span><span class="no">Foo</span><span class="p">)</span> <span class="k">do</span>
<span class="k">def</span> <span class="nf">bar</span>
<span class="mi">42</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">b</span> <span class="o">=</span> <span class="nb">binding</span>
<span class="nb">eval</span><span class="p">(</span><span class="s1">'using M'</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
<span class="nb">puts</span> <span class="nb">eval</span><span class="p">(</span><span class="s1">'Foo.new.bar'</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
<span class="c1"># expected:</span>
<span class="c1"># 42</span>
<span class="c1">#</span>
<span class="c1"># actual 2.0.0:</span>
<span class="c1"># refinement2.rb:4: warning: Refinements are experimental, and the behavior may change in future versions of Ruby!</span>
<span class="c1"># 42</span>
<span class="c1">#</span>
<span class="c1"># actual 2.1.5:</span>
<span class="c1"># refinement2.rb:11:in `<main>': undefined method `bar' for #<Foo:0x007fc47c865568> (NoMethodError)</span>
<span class="c1"># from refinement2.rb:13:in `eval'</span>
<span class="c1"># from refinement2.rb:13:in `<main>'</span>
<span class="c1">#</span>
<span class="c1"># actual 2.2.0:</span>
<span class="c1"># refinement2.rb:11:in `<main>': undefined method `bar' for #<Foo:0x007fa1f0852138> (NoMethodError)</span>
<span class="c1"># from refinement2.rb:13:in `eval'</span>
<span class="c1"># from refinement2.rb:13:in `<main>'</span>
</code></pre> Ruby master - Bug #10818: Extrange behaviour when apliying a refinement inside evalhttps://bugs.ruby-lang.org/issues/10818?journal_id=513612015-02-03T07:51:45Zshugo (Shugo Maeda)
<ul><li><strong>Status</strong> changed from <i>Open</i> to <i>Assigned</i></li><li><strong>Assignee</strong> set to <i>shugo (Shugo Maeda)</i></li></ul> Ruby master - Bug #10818: Extrange behaviour when apliying a refinement inside evalhttps://bugs.ruby-lang.org/issues/10818?journal_id=513632015-02-03T08:33:11Zshugo (Shugo Maeda)
<ul></ul><p>Seiei Higa wrote:</p>
<blockquote>
<p>So, I expect following code works fine, but it raises <code>NoMethodError</code> in ruby 2.1.5, 2.2.0</p>
</blockquote>
<p>Refinements should be activated in a lexical scope, so NoMethodError should be raised in that case.</p>
<p>The problem originally reported is considered to be a bug, but it's difficult to fix because<br>
the environment of binding is updated by eval to share local variables (see vm_eval.c:1293),<br>
and refinement activation information is stored in the same area.</p>
<p>Ko1, do you have any idea to fix this bug?</p> Ruby master - Bug #10818: Extrange behaviour when apliying a refinement inside evalhttps://bugs.ruby-lang.org/issues/10818?journal_id=513642015-02-03T10:06:23Zhanachin (Seiei Miyagi)hanachin@gmail.com
<ul></ul><blockquote>
<p>Refinements should be activated in a lexical scope, so NoMethodError should be raised in that case.</p>
</blockquote>
<p>How about this case?</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">C</span><span class="p">;</span> <span class="k">end</span>
<span class="k">module</span> <span class="nn">M</span>
<span class="n">refine</span><span class="p">(</span><span class="no">C</span><span class="p">)</span> <span class="k">do</span>
<span class="k">def</span> <span class="nf">foo</span>
<span class="mi">42</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">using</span> <span class="no">M</span>
<span class="vg">$b</span> <span class="o">=</span> <span class="nb">binding</span>
<span class="k">end</span>
<span class="nb">puts</span> <span class="vg">$b</span><span class="p">.</span><span class="nf">eval</span><span class="p">(</span><span class="s1">'C.new.foo'</span><span class="p">)</span>
<span class="c1"># result in 2.2.0:</span>
<span class="c1"># 42</span>
</code></pre>
<p><a href="http://www.ruby-doc.org/core-2.2.0/Binding.html" class="external">The docs of Binding</a> says</p>
<blockquote>
<p>Objects of class Binding encapsulate the execution context at some particular place in the code and retain this context for future use. The variables, methods, value of self, and possibly an iterator block that can be accessed in this context are all retained.</p>
</blockquote>
<p>and <a href="http://www.ruby-doc.org/core-2.2.0/Binding.html#method-i-eval" class="external">docs of Binding#eval</a> says</p>
<blockquote>
<p>Evaluates the Ruby expression(s) in string, in the binding’s context.</p>
</blockquote>
<p>It's sounds good to retain refinements in binding's context.</p> Ruby master - Bug #10818: Extrange behaviour when apliying a refinement inside evalhttps://bugs.ruby-lang.org/issues/10818?journal_id=513742015-02-04T00:40:51Zpabloh (Pablo Herrero)pablodherrero@gmail.com
<ul></ul><p>Does it make any difference that the refinement at Seiei's example was already active before the string evaluation?.</p> Ruby master - Bug #10818: Extrange behaviour when apliying a refinement inside evalhttps://bugs.ruby-lang.org/issues/10818?journal_id=513752015-02-04T00:45:58Zpabloh (Pablo Herrero)pablodherrero@gmail.com
<ul></ul><p>Seiei Higa wrote:</p>
<blockquote>
<p>How about this case?</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">C</span><span class="p">;</span> <span class="k">end</span>
<span class="k">module</span> <span class="nn">M</span>
<span class="n">refine</span><span class="p">(</span><span class="no">C</span><span class="p">)</span> <span class="k">do</span>
<span class="k">def</span> <span class="nf">foo</span>
<span class="mi">42</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">using</span> <span class="no">M</span>
<span class="vg">$b</span> <span class="o">=</span> <span class="nb">binding</span>
<span class="k">end</span>
<span class="nb">puts</span> <span class="vg">$b</span><span class="p">.</span><span class="nf">eval</span><span class="p">(</span><span class="s1">'C.new.foo'</span><span class="p">)</span>
<span class="c1"># result in 2.2.0:</span>
<span class="c1"># 42</span>
</code></pre>
</blockquote>
<p>OTOH that's also allowing you to leak the active refinements outside the lexical scope...</p> Ruby master - Bug #10818: Extrange behaviour when apliying a refinement inside evalhttps://bugs.ruby-lang.org/issues/10818?journal_id=513782015-02-04T02:47:26Zshugo (Shugo Maeda)
<ul></ul><p>Pablo Herrero wrote:</p>
<blockquote>
<p>Does it make any difference that the refinement at Seiei's example was already active before the string evaluation?.</p>
</blockquote>
<p>If eval('using M', b) in Seiei's example is changed to eval('x = 1; using M', b),<br>
refinements are activated in the subsequent eval.<br>
It's because b's environment is updated to capture the new local variable x.</p> Ruby master - Bug #10818: Extrange behaviour when apliying a refinement inside evalhttps://bugs.ruby-lang.org/issues/10818?journal_id=513792015-02-04T03:01:45Zshugo (Shugo Maeda)
<ul><li><strong>Assignee</strong> changed from <i>shugo (Shugo Maeda)</i> to <i>matz (Yukihiro Matsumoto)</i></li></ul><p>Seiei Higa wrote:</p>
<blockquote>
<blockquote>
<p>Refinements should be activated in a lexical scope, so NoMethodError should be raised in that case.</p>
</blockquote>
<p>How about this case?</p>
</blockquote>
<p>It might be a bug too.</p>
<blockquote>
<p><a href="http://www.ruby-doc.org/core-2.2.0/Binding.html" class="external">The docs of Binding</a> says</p>
<blockquote>
<p>Objects of class Binding encapsulate the execution context at some particular place in the code and retain this context for future use. The variables, methods, value of self, and possibly an iterator block that can be accessed in this context are all retained.</p>
</blockquote>
<p>and <a href="http://www.ruby-doc.org/core-2.2.0/Binding.html#method-i-eval" class="external">docs of Binding#eval</a> says</p>
<blockquote>
<p>Evaluates the Ruby expression(s) in string, in the binding’s context.</p>
</blockquote>
<p>It's sounds good to retain refinements in binding's context.</p>
</blockquote>
<p>The documentation of Binding should not justify the behavior of refinements,<br>
because it was written before refinements are introduced into Ruby.</p>
<p>The original version of refinements are designed to be a more dynamic feature,<br>
but it was changed to be more static to avoid confusion caused by implicit<br>
refinement activation.</p>
<p>I'd like to hear Matz's opinion.</p> Ruby master - Bug #10818: Extrange behaviour when apliying a refinement inside evalhttps://bugs.ruby-lang.org/issues/10818?journal_id=513802015-02-04T03:56:49Zpabloh (Pablo Herrero)pablodherrero@gmail.com
<ul></ul><p>Shugo Maeda wrote:</p>
<blockquote>
<p>Pablo Herrero wrote:</p>
<blockquote>
<p>Does it make any difference that the refinement at Seiei's example was already active before the string evaluation?.</p>
</blockquote>
<p>If eval('using M', b) in Seiei's example is changed to eval('x = 1; using M', b),<br>
refinements are activated in the subsequent eval.<br>
It's because b's environment is updated to capture the new local variable x.</p>
</blockquote>
<p>I followed you there, but I meant the example where he activated the refinement outside the string and then stored the binding at the global variable. Sorry if I wasn't clear enough.</p> Ruby master - Bug #10818: Extrange behaviour when apliying a refinement inside evalhttps://bugs.ruby-lang.org/issues/10818?journal_id=517642015-03-05T02:52:54Zshugo (Shugo Maeda)
<ul><li><strong>Assignee</strong> changed from <i>matz (Yukihiro Matsumoto)</i> to <i>shugo (Shugo Maeda)</i></li></ul><p>Shugo Maeda wrote:</p>
<blockquote>
<p>I'd like to hear Matz's opinion.</p>
</blockquote>
<p>I talked with Matz, and he said that a binding should keep refinements activation<br>
information and the refinements should be activated in subsequent eval calls with<br>
the binding.</p>
<p>So I'll change the behavior of eval as follows:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">module</span> <span class="nn">M</span>
<span class="n">refine</span> <span class="no">String</span> <span class="k">do</span>
<span class="k">def</span> <span class="nf">foobar</span><span class="p">;</span> <span class="nb">puts</span> <span class="s1">'foobar'</span><span class="p">;</span> <span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">some_binding</span> <span class="o">=</span> <span class="k">class</span> <span class="nc">A</span><span class="p">;</span> <span class="nb">binding</span><span class="p">;</span> <span class="k">end</span>
<span class="n">str1</span> <span class="o">=</span> <span class="o"><<</span><span class="no">EOF</span><span class="sh">
using M
'str'.foobar
</span><span class="no">EOF</span>
<span class="n">str2</span> <span class="o">=</span> <span class="o"><<</span><span class="no">EOF</span><span class="sh">
'str'.foobar
</span><span class="no">EOF</span>
<span class="nb">eval</span> <span class="n">str1</span><span class="p">,</span> <span class="n">some_binding</span> <span class="c1"># foobar</span>
<span class="nb">eval</span> <span class="n">str2</span><span class="p">,</span> <span class="n">some_binding</span> <span class="c1"># foobar (No exception is raised)</span>
</code></pre> Ruby master - Bug #10818: Extrange behaviour when apliying a refinement inside evalhttps://bugs.ruby-lang.org/issues/10818?journal_id=517652015-03-05T02:56:35Zshugo (Shugo Maeda)
<ul><li><strong>Status</strong> changed from <i>Assigned</i> to <i>Closed</i></li><li><strong>% Done</strong> changed from <i>0</i> to <i>100</i></li></ul><p>Applied in changeset r49851.</p>
<hr>
<ul>
<li>vm_eval.c (eval_string_with_cref): A binding should keep<br>
refinements activation information and the refinements should be<br>
activated in subsequent eval calls with the binding.<br>
<a href="/issues/10818">[ruby-core:67945]</a> [Bug <a class="issue tracker-1 status-5 priority-4 priority-default closed" title="Bug: Extrange behaviour when apliying a refinement inside eval (Closed)" href="https://bugs.ruby-lang.org/issues/10818">#10818</a>]</li>
</ul>