Ruby Issue Tracking System: Issueshttps://bugs.ruby-lang.org/https://bugs.ruby-lang.org/favicon.ico?17113305112024-03-05T15:21:08ZRuby Issue Tracking System
Redmine Ruby master - Bug #20325 (Open): Enumerator.product.size bug with zero * infinite enumeratorshttps://bugs.ruby-lang.org/issues/203252024-03-05T15:21:08Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Enumerator</span><span class="p">.</span><span class="nf">product</span><span class="p">([],</span> <span class="mi">1</span><span class="o">..</span><span class="p">).</span><span class="nf">to_a</span> <span class="c1"># => [] (OK)</span>
<span class="no">Enumerator</span><span class="p">.</span><span class="nf">product</span><span class="p">([],</span> <span class="mi">1</span><span class="o">..</span><span class="p">).</span><span class="nf">size</span> <span class="c1"># => Infinity (Should be 0)</span>
</code></pre> Ruby master - Bug #18018 (Closed): Float#floor / truncate sometimes result that is too small.https://bugs.ruby-lang.org/issues/180182021-07-01T22:53:33Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="mf">291.4</span><span class="p">.</span><span class="nf">floor</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="c1"># => 291.4 (ok)</span>
<span class="mf">291.4</span><span class="p">.</span><span class="nf">floor</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="c1"># => 291.39 (not ok)</span>
<span class="mf">291.4</span><span class="p">.</span><span class="nf">floor</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> <span class="c1"># => 291.4 (ok)</span>
<span class="mf">291.4</span><span class="p">.</span><span class="nf">floor</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span> <span class="c1"># => 291.4 (ok)</span>
<span class="mf">291.4</span><span class="p">.</span><span class="nf">floor</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span> <span class="c1"># => 291.39999 (not ok)</span>
<span class="mf">291.4</span><span class="p">.</span><span class="nf">floor</span><span class="p">(</span><span class="mi">6</span><span class="p">)</span> <span class="c1"># => 291.4 (ok)</span>
</code></pre>
<p><code>g = f.floor(n)</code>, for <code>n > 0</code> must return the highest float that has the correct properties:</p>
<ul>
<li>
<code>g</code> <= <code>f</code>
</li>
<li>
<code>g</code>'s decimal string representation has at most <code>n</code> digits</li>
</ul>
<p>I'll note that <code>floor</code> should be stable, i.e. <code>f.floor(n).floor(n) == f.floor(n)</code> for all <code>f</code> and <code>n</code>.</p>
<p>Same idea for <code>truncate</code>, except for negative numbers (where <code>(-f).truncate(n) == -(f.floor(n))</code> for positive <code>f</code>).</p>
<p>Noticed by Eustáquio Rangel but posted on the mailing list.</p>
<p>Please do not reply that I need to learn how floats work. Note that example given in doc <code>(0.3/0.1).floor == 2</code> is not this issue, since <code>0.3/0.1 #=> 2.9999999999999996</code></p> Ruby master - Bug #17600 (Closed): lib/benchmark should use `$stdout` instead of `STDOUT`https://bugs.ruby-lang.org/issues/176002021-01-31T17:09:39Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Unless there is objection, I'll change all uses of <code>STDOUT</code> to <code>$stdout</code> in <code>lib/benchmark</code>, to allow redirection to other io.</p>
<p>See <a href="https://github.com/ruby/benchmark/issues/5" class="external">https://github.com/ruby/benchmark/issues/5</a></p> Ruby master - Bug #17577 (Closed): Segfault when sending some Exceptions to a Ractorhttps://bugs.ruby-lang.org/issues/175772021-01-24T19:03:45Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>The following segfaults:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">r</span> <span class="o">=</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="n">receive</span> <span class="p">}</span>
<span class="k">begin</span>
<span class="n">foo</span> <span class="c1"># => raises a NoMethodError</span>
<span class="k">rescue</span> <span class="no">Exception</span> <span class="o">=></span> <span class="n">e</span>
<span class="n">r</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="n">e</span><span class="p">)</span>
<span class="k">end</span>
<span class="nb">p</span> <span class="n">r</span><span class="p">.</span><span class="nf">take</span>
</code></pre>
<p>Note that some exceptions are ok:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">raise</span> <span class="c1"># => ok</span>
<span class="k">raise</span> <span class="no">NoMethodError</span><span class="p">,</span> <span class="s1">'...'</span> <span class="c1"># => ok</span>
<span class="s1">'s'</span><span class="p">.</span><span class="nf">to_i</span><span class="p">(</span><span class="o">-</span><span class="mi">2</span><span class="p">)</span> <span class="c1"># => ok</span>
<span class="n">foo</span> <span class="c1"># => segfault</span>
<span class="no">Xyz</span> <span class="c1"># => segfault</span>
</code></pre>
<p>Present on 3.0.0p0 as well as master (ruby 3.1.0dev (2021-01-24T14:26:11Z master 30f11e73c4) [x86_64-darwin18])</p>
<pre><code>-- Control frame information -----------------------------------------------
c:0004 p:0003 s:0019 e:000018 METHOD <internal:ractor>:583
c:0003 p:0025 s:0012 e:000011 RESCUE ractor.rb:5
c:0002 p:0025 s:0008 E:000680 EVAL ractor.rb:2 [FINISH]
c:0001 p:0000 s:0003 E:001b80 (none) [FINISH]
-- C level backtrace information -------------------------------------------
/Users/mal/.rbenv/versions/dev/bin/ruby(rb_vm_bugreport+0x732) [0x105de8672]
/Users/mal/.rbenv/versions/dev/bin/ruby(rb_bug_for_fatal_signal+0x1dc) [0x105bf671c]
/Users/mal/.rbenv/versions/dev/bin/ruby(sigsegv+0x5b) [0x105d3c87b]
/usr/lib/system/libsystem_platform.dylib(_sigtramp+0x1d) [0x7fff61425b5d]
[0x34]
/Users/mal/.rbenv/versions/dev/bin/ruby(rb_objspace_reachable_objects_from+0xa3) [0x105c19193]
/Users/mal/.rbenv/versions/dev/bin/ruby(obj_traverse_replace_i+0x38d) [0x105cedb0d]
/Users/mal/.rbenv/versions/dev/bin/ruby(obj_traverse_replace_i+0x46f) [0x105cedbef]
/Users/mal/.rbenv/versions/dev/bin/ruby(ractor_send+0x18b) [0x105ce8fdb]
/Users/mal/.rbenv/versions/dev/bin/ruby(vm_exec_core+0x77ea) [0x105dbfcaa]
/Users/mal/.rbenv/versions/dev/bin/ruby(rb_vm_exec+0xb36) [0x105dd0916]
/Users/mal/.rbenv/versions/dev/bin/ruby(rb_ec_exec_node+0x14d) [0x105c01aad]
/Users/mal/.rbenv/versions/dev/bin/ruby(ruby_run_node+0x57) [0x105c018f7]
/Users/mal/.rbenv/versions/dev/bin/ruby(main+0x71) [0x105b51141]
</code></pre> Ruby master - Bug #17543 (Closed): Ractor isolation broken by `self` in shareable prochttps://bugs.ruby-lang.org/issues/175432021-01-15T07:39:58Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Discussing with <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/8409">@MaxLap (Maxime Lapointe)</a> we realized that the <code>self</code> in a shareable proc is not properly isolated:</p>
<pre><code>class Foo
attr_accessor :x
def pr
Ractor.make_shareable(Proc.new { self })
end
end
f = Foo.new
f.x = [1, 2, 3]
Ractor.new(f.pr) { |pr| pr.call.x << :oops }
p f.x # => [1, 2, 3, :oops]
</code></pre>
<p>If the <code>self</code> refers to a shareable object then it's fine, but for non-shareable objects it has to be reset to <code>nil</code> or to a global shareable object that would have an instructive <code>inspect</code>.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Ractor</span><span class="o">::</span><span class="no">DETACHED_SELF</span> <span class="o">=</span> <span class="no">Object</span><span class="p">.</span><span class="nf">new</span>
<span class="k">def</span> <span class="nf"><<</span> <span class="no">Ractor</span><span class="o">::</span><span class="no">DETACHED_SELF</span>
<span class="k">def</span> <span class="nf">inspect</span>
<span class="s1">'<#detached self>'</span>
<span class="k">end</span>
<span class="k">alias</span> <span class="nb">to_s</span> <span class="nb">inspect</span>
<span class="k">end</span>
<span class="no">Ractor</span><span class="o">::</span><span class="no">DETACHED_SELF</span><span class="p">.</span><span class="nf">freeze</span>
</code></pre> Ruby master - Bug #17531 (Closed): `did_you_mean` not Ractor friendlyhttps://bugs.ruby-lang.org/issues/175312021-01-12T19:30:56Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>The gem <code>did_you_mean</code> uses a class instance variable that does not work with Ractor.</p>
<pre><code>$ RUBYOPT='--disable-did_you_mean' ruby -W0 -e 'Ractor.new{ begin ; nil + 42; rescue Exception => e; e.to_s end}.take'
# => prints nothing (ok)
$ ruby -W0 -e 'Ractor.new{ begin ; nil + 42; rescue Exception => e; e.to_s end}.take'
# Prints
/Users/mal/.rbenv/versions/3.0.0/lib/ruby/3.0.0/did_you_mean.rb:102:in `formatter'
/Users/mal/.rbenv/versions/3.0.0/lib/ruby/3.0.0/did_you_mean/core_ext/name_error.rb:9:in `to_s'
-e:1:in `rescue in block in <main>'
-e:1:in `block in <main>'
# (not ok)
</code></pre> Ruby master - Bug #17506 (Open): Ractor isolation broken by ThreadGrouphttps://bugs.ruby-lang.org/issues/175062021-01-03T20:05:43Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Ractors currently share the ThreadGroup.</p>
<p>This doesn't seem very useful as there is no possible communication between the Threads of different Ractors.</p>
<p>It is also an isolation error:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">ThreadGroup</span><span class="p">.</span><span class="nf">attr_accessor</span> <span class="ss">:foo</span>
<span class="n">var</span> <span class="o">=</span> <span class="no">Thread</span><span class="p">.</span><span class="nf">current</span><span class="p">.</span><span class="nf">group</span><span class="p">.</span><span class="nf">foo</span> <span class="o">=</span> <span class="p">[</span><span class="ss">:example</span><span class="p">]</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="no">Thread</span><span class="p">.</span><span class="nf">current</span><span class="p">.</span><span class="nf">group</span><span class="p">.</span><span class="nf">foo</span> <span class="o"><<</span> <span class="p">[</span><span class="ss">:oops</span><span class="p">]</span> <span class="p">}.</span><span class="nf">take</span>
<span class="n">var</span> <span class="c1"># => [:example, [:oops]]</span>
</code></pre>
<p>Should <code>Ractor.new</code> create a new <code>ThreadGroup</code>? Should <code>ThreadGroup</code> not have (non-shareable) instance variables? Or should <code>Ractor.new { Thread.current.group }.take</code> be <code>nil</code>? See also <a href="https://bugs.ruby-lang.org/issues/17505" class="external">https://bugs.ruby-lang.org/issues/17505</a> about <code>nil</code>.</p>
<p>Note that <code>Ractor</code> respects the <code>ThreadGroup</code>'s state:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Thread</span><span class="p">.</span><span class="nf">current</span><span class="p">.</span><span class="nf">group</span><span class="p">.</span><span class="nf">enclose</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="no">Thread</span><span class="p">.</span><span class="nf">current</span><span class="p">.</span><span class="nf">group</span><span class="p">.</span><span class="nf">add</span><span class="p">(</span><span class="no">Thread</span><span class="p">.</span><span class="nf">current</span><span class="p">)</span> <span class="p">}.</span><span class="nf">take</span> <span class="c1"># => can't move to the enclosed thread group</span>
<span class="no">Thread</span><span class="p">.</span><span class="nf">current</span><span class="p">.</span><span class="nf">group</span><span class="p">.</span><span class="nf">freeze</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span> <span class="p">{}</span> <span class="c1"># => ThreadError (can't start a new thread (frozen ThreadGroup))</span>
</code></pre>
<p>I am not sure what is the best behavior as I don't have enough experience with how ThreadGroups are used, especially enclosed ThreadGroups.</p> Ruby master - Bug #17505 (Closed): Can `Thread#group` actually be `nil`?https://bugs.ruby-lang.org/issues/175052021-01-03T19:41:27Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Is there a circumstance where <code>Thread#group</code> could actually be <code>nil</code>?</p>
<p>The documentation says so, there seems to be source code for this, but I can find no test or RubySpec for this and I don't see anywhere in the <code>ThreadGroup</code> API that could allow this.</p> Ruby master - Bug #17497 (Closed): Ractor performance issuehttps://bugs.ruby-lang.org/issues/174972020-12-31T21:48:50Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>There's a strange performance issue with Ractor (at least on MacOS, didn't run on other OS).</p>
<p>I ran a benchmark doing 3 different types of work:</p>
<ul>
<li>"fib": method calls (naive fibonacci calculation)</li>
<li>"cpu": <code>(0...1000).inject(:+)</code>
</li>
<li>"sleep": call <code>sleep</code>
</li>
</ul>
<p>I get the kind of results I was excepting for the <code>fib</code> and for sleeping, but the results for the "cpu" workload show a problem.</p>
<p>It is so slow that my pure Ruby backport (using Threads) is 65x faster 😮 on my Mac Pro (despite having 6 cores). Expected results would be 6x slower, so in that case Ractor is 400x slower than it should 😿</p>
<p>On my MacBook (2 cores) the results are not as bad, the <code>cpu</code> workload is 3x faster with my pure-Ruby backport (only) instead of ~2x slower, so the factor is 6x too slow.</p>
<pre><code>$ gem install backports
Successfully installed backports-3.20.0
1 gem installed
$ ruby ractor_test.rb
<internal:ractor>:267: warning: Ractor is experimental, and the behavior may change in future versions of Ruby! Also there are many implementation issues.
fib: 110 ms | cpu: 22900 ms | sleep: 206 ms
$ B=t ruby ractor_test.rb
Using pure Ruby implementation
fib: 652 ms | cpu: 337 ms | sleep: 209 ms
</code></pre>
<p>Notice the <code>sleep</code> run takes similar time, which is good, and <code>fib</code> is ~6x faster on my 6-core CPU (and ~2x faster on my 2-core MacBook), again that's good as the pure ruby version uses Threads and thus runs with a single GVL.</p>
<p>The <code>cpu</code> version is the problem.</p>
<p>Script is here: <a href="https://gist.github.com/marcandre/bfed626e538a3d0fc7cad38dc026cf0e" class="external">https://gist.github.com/marcandre/bfed626e538a3d0fc7cad38dc026cf0e</a></p> Ruby master - Bug #17428 (Closed): Method#inspect bad output for class methodshttps://bugs.ruby-lang.org/issues/174282020-12-23T00:35:55Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<pre><code>$ $ ruby -e 'p String.method(:prepend)'
# 2.7.0:
#<Method: String.prepend(*)>
# 3.0.0:
#<Method: #<Class:Object>(Module)#prepend(*)>
</code></pre>
<p>@jeremyevans found it shows the method as pertaining to one level too high (which is good for objects as we don't want to show the singleton class there, but not for classes).</p>
<p>Probably due to <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> Ruby master - Bug #17379 (Closed): Refinement with modules redefinition bughttps://bugs.ruby-lang.org/issues/173792020-12-09T04:21:11Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Depending on the circumstance, a refinement can be modified even after being used:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">foo</span>
<span class="p">[</span><span class="ss">:base</span><span class="p">]</span>
<span class="k">end</span>
<span class="k">module</span> <span class="nn">M</span>
<span class="k">def</span> <span class="nf">foo</span>
<span class="k">super</span> <span class="o"><<</span> <span class="ss">:M</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">module</span> <span class="nn">Ext</span>
<span class="n">refine</span> <span class="no">Object</span> <span class="k">do</span>
<span class="kp">include</span> <span class="no">M</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">using</span> <span class="no">Ext</span>
<span class="nb">p</span> <span class="s1">'asd'</span><span class="p">.</span><span class="nf">foo</span> <span class="k">unless</span> <span class="no">ENV</span><span class="p">[</span><span class="s1">'SKIP'</span><span class="p">]</span> <span class="c1"># => [:base, :M] (ok)</span>
<span class="k">module</span> <span class="nn">M</span>
<span class="k">def</span> <span class="nf">foo</span>
<span class="k">super</span> <span class="o"><<</span> <span class="ss">:new_ref</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="nb">p</span> <span class="s1">'asd'</span><span class="p">.</span><span class="nf">foo</span> <span class="c1"># => depends (not ok)</span>
</code></pre>
<p>Running this gives:</p>
<pre><code>$ ruby refinement.rb
[:base, :M]
[:base, :M] # => ok
$ SKIP=t ruby refinement.rb
[:base, :new_ref] # => should be [:base, :M]
</code></pre> Ruby master - Bug #17368 (Closed): `Ractor.select()` loops foreverhttps://bugs.ruby-lang.org/issues/173682020-12-05T07:41:44Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I propose it raises an error in <a href="https://github.com/ruby/ruby/pull/3848" class="external">https://github.com/ruby/ruby/pull/3848</a></p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Ractor</span><span class="p">.</span><span class="nf">select</span> <span class="c1"># => loops</span>
<span class="c1"># after</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">select</span> <span class="c1"># => ArgumentError, "specify at least one ractor or `yield_value`"</span>
</code></pre> Ruby master - Bug #17366 (Closed): Ractor odd issue with timeout + receive + sleep + takehttps://bugs.ruby-lang.org/issues/173662020-12-05T06:58:11Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I believe the following behavior is incorrect:</p>
<pre><code>ruby -r timeout -e 'r = Ractor.new { Timeout.timeout(0.1) { sleep(1) } rescue :timeout }; p r.take'
# => :timeout (ok)
ruby -r timeout -e 'r = Ractor.new { Timeout.timeout(0.1) { sleep(1) } rescue :timeout }; sleep(0.2); p r.take'
# => :timeout (ok)
ruby -r timeout -e 'r = Ractor.new { Timeout.timeout(0.1) { Ractor.receive } rescue :timeout }; p r.take'
# => :timeout (ok)
ruby -r timeout -e 'r = Ractor.new { Timeout.timeout(0.1) { Ractor.receive } rescue :timeout }; sleep(0.2); p r.take'
<internal:ractor>:130:in `take': The outgoing-port is already closed (Ractor::ClosedError) # => not ok
</code></pre> Ruby master - Bug #17359 (Open): Ractor copy mode is not Ractor-safehttps://bugs.ruby-lang.org/issues/173592020-12-01T08:29:37Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>It should not be possible to mutate an object across Ractors, but the copy mode allows it currently:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">Foo</span>
<span class="nb">attr_accessor</span> <span class="ss">:x</span>
<span class="k">def</span> <span class="nf">initialize_copy</span><span class="p">(</span><span class="o">*</span><span class="p">)</span>
<span class="vg">$last</span> <span class="o">=</span> <span class="nb">self</span>
<span class="k">super</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">o</span> <span class="o">=</span> <span class="no">Foo</span><span class="p">.</span><span class="nf">new</span>
<span class="n">o</span><span class="p">.</span><span class="nf">x</span> <span class="o">=</span> <span class="mi">42</span>
<span class="n">r</span> <span class="o">=</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">o</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">copy</span><span class="o">|</span>
<span class="nb">puts</span> <span class="n">copy</span><span class="p">.</span><span class="nf">x</span> <span class="c1"># => 42</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">yield</span> <span class="ss">:sync</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">yield</span> <span class="ss">:sync</span>
<span class="nb">puts</span> <span class="n">copy</span><span class="p">.</span><span class="nf">x</span> <span class="c1"># => 666</span>
<span class="k">end</span>
<span class="n">r</span><span class="p">.</span><span class="nf">take</span> <span class="c1"># => :sync</span>
<span class="vg">$last</span><span class="p">.</span><span class="nf">x</span> <span class="o">=</span> <span class="mi">666</span>
<span class="n">r</span><span class="p">.</span><span class="nf">take</span> <span class="c1"># => :sync</span>
<span class="n">r</span><span class="p">.</span><span class="nf">take</span>
</code></pre>
<p>Maybe the <code>copy</code> object should be marked as moved?</p> Ruby master - Bug #17344 (Closed): `Ractor#shareable?` confused by recursive structureshttps://bugs.ruby-lang.org/issues/173442020-11-26T09:46:49Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">y</span> <span class="o">=</span> <span class="p">[];</span> <span class="n">x</span> <span class="o">=</span> <span class="p">[</span><span class="n">y</span><span class="p">,</span> <span class="p">{}].</span><span class="nf">freeze</span><span class="p">;</span> <span class="n">y</span> <span class="o"><<</span> <span class="n">x</span><span class="p">;</span> <span class="n">y</span><span class="p">.</span><span class="nf">freeze</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">shareable?</span><span class="p">(</span><span class="n">y</span><span class="p">)</span> <span class="c1"># => false, ok, the `{}` is not frozen</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">shareable?</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="c1"># => false, ok</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">shareable?</span><span class="p">(</span><span class="n">y</span><span class="p">)</span> <span class="c1"># => true, not ok!</span>
</code></pre>
<p>The error is that we can not mark anything as shareable until the whole tree has been searched successfully. Only when the full traversal is successful, then all visited objects can be marked as shareable. There might be a more clever way, but I couldn't think of one when working on my backport.</p> Ruby master - Bug #17343 (Closed): Ractor can't clone frozen structureshttps://bugs.ruby-lang.org/issues/173432020-11-26T09:44:49Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span><span class="p">([[]].</span><span class="nf">freeze</span><span class="p">)</span> <span class="p">{}</span> <span class="c1"># => FrozenError</span>
</code></pre>
<p>See <a href="https://github.com/ruby/ruby/pull/3817" class="external">https://github.com/ruby/ruby/pull/3817</a></p> Ruby master - Bug #17310 (Closed): Closed ractors should diehttps://bugs.ruby-lang.org/issues/173102020-11-08T03:17:25Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>While backporting Ractors, I found this issue:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="mi">10</span><span class="p">.</span><span class="nf">times</span> <span class="p">{</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="nb">sleep</span><span class="p">(</span><span class="mf">0.1</span><span class="p">)</span> <span class="p">}</span> <span class="p">}</span>
<span class="nb">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="nb">puts</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">count</span> <span class="c1"># => 1, ok</span>
<span class="c1"># but:</span>
<span class="mi">10</span><span class="p">.</span><span class="nf">times</span> <span class="p">{</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="nb">sleep</span><span class="p">(</span><span class="mf">0.1</span><span class="p">)</span> <span class="p">}.</span><span class="nf">close</span> <span class="p">}</span>
<span class="nb">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">count</span> <span class="c1"># => 11, should be 1</span>
</code></pre> Ruby master - Bug #17124 (Closed): Wrong "ambiguous first argument" warninghttps://bugs.ruby-lang.org/issues/171242020-08-18T20:02:54Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<pre><code class="sh syntaxhl" data-language="sh"><span class="nv">$ </span>ruby <span class="nt">-v</span> <span class="nt">-e</span> <span class="s2">"x='a'; x.match? /[a-z]/"</span>
ruby 2.8.0dev <span class="o">(</span>2020-07-30T14:07:06Z master 352895b751<span class="o">)</span> <span class="o">[</span>x86_64-darwin18]
<span class="nt">-e</span>:1: warning: ambiguous first argument<span class="p">;</span> put parentheses or a space even after <span class="sb">`</span>/<span class="s1">' operator
</span></code></pre>
<p>There is no <code>/</code> operator in there and there is also no ambiguity as adding a space after the first <code>/</code> is a syntax error.</p>
<p>Is it possible to remove the warning altogether when the argument is lexed as a regexp?</p>
<p>The message could use a rewording too, maybe "ambiguous first argument; put parentheses around argument or add a space after `/' operator"</p> Ruby master - Bug #17092 (Closed): Array#flatten with finite depth should flatten recursive arrayshttps://bugs.ruby-lang.org/issues/170922020-07-30T12:29:24Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Recursive arrays can not be flattened currently:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">a</span> <span class="o">=</span> <span class="p">[];</span> <span class="n">a</span> <span class="o"><<</span> <span class="n">a</span>
<span class="n">a</span><span class="p">.</span><span class="nf">flatten</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="c1"># => tried to flatten recursive array</span>
</code></pre>
<p>The only valid reason to raise an error for recursive arrays is for flatten with no argument (or negative argument); the case for finite-depth flatten is not problematic.</p>
<p>This fix has the bonus of speeding up the finite-depth case in general.</p>
<p>I will merge <a href="https://github.com/ruby/ruby/pull/3374" class="external">https://github.com/ruby/ruby/pull/3374</a>, <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/4">@nobu (Nobuyoshi Nakada)</a> asked for backports.</p> Ruby master - Bug #17031 (Closed): `Kernel#caller_locations(m, n)` should be optimizedhttps://bugs.ruby-lang.org/issues/170312020-07-14T19:07:29Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p><code>Kernel#caller_locations(1, 1)</code> currently appears to needlessly allocate memory for the whole backtrace.</p>
<p>It allocates ~20kB for a 800-deep stacktrace, vs 1.6 kB for a shallow backtrace.<br>
It is also much slower for long stacktraces: about 7x slower for a 800-deep backtrace than for a shallow one.</p>
<p>Test used:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">do_something</span>
<span class="n">location</span> <span class="o">=</span> <span class="n">caller_locations</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">).</span><span class="nf">first</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">test</span><span class="p">(</span><span class="n">depth</span><span class="p">,</span> <span class="n">trigger</span><span class="p">)</span>
<span class="n">do_something</span> <span class="k">if</span> <span class="n">depth</span> <span class="o">==</span> <span class="n">trigger</span>
<span class="nb">test</span><span class="p">(</span><span class="n">depth</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="n">trigger</span><span class="p">)</span> <span class="k">unless</span> <span class="n">depth</span> <span class="o">==</span> <span class="mi">0</span>
<span class="k">end</span>
<span class="nb">require</span> <span class="s1">'benchmark/ips'</span>
<span class="no">Benchmark</span><span class="p">.</span><span class="nf">ips</span> <span class="k">do</span> <span class="o">|</span><span class="n">x</span><span class="o">|</span>
<span class="n">x</span><span class="p">.</span><span class="nf">report</span> <span class="p">(</span><span class="ss">:short_backtrace</span> <span class="p">)</span> <span class="p">{</span><span class="nb">test</span><span class="p">(</span><span class="mi">800</span><span class="p">,</span><span class="mi">800</span><span class="p">)}</span>
<span class="n">x</span><span class="p">.</span><span class="nf">report</span> <span class="p">(</span><span class="ss">:long_backtrace</span> <span class="p">)</span> <span class="p">{</span><span class="nb">test</span><span class="p">(</span><span class="mi">800</span><span class="p">,</span> <span class="mi">0</span><span class="p">)}</span>
<span class="n">x</span><span class="p">.</span><span class="nf">report</span> <span class="p">(</span><span class="ss">:no_caller_locations</span><span class="p">)</span> <span class="p">{</span><span class="nb">test</span><span class="p">(</span><span class="mi">800</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">)}</span>
<span class="k">end</span>
<span class="nb">require</span> <span class="s1">'memory_profiler'</span>
<span class="no">MemoryProfiler</span><span class="p">.</span><span class="nf">report</span> <span class="p">{</span> <span class="nb">test</span><span class="p">(</span><span class="mi">800</span><span class="p">,</span><span class="mi">800</span><span class="p">)</span> <span class="p">}.</span><span class="nf">pretty_print</span><span class="p">(</span><span class="ss">scale_bytes: </span><span class="kp">true</span><span class="p">,</span> <span class="ss">detailed_report: </span><span class="kp">false</span><span class="p">)</span>
<span class="no">MemoryProfiler</span><span class="p">.</span><span class="nf">report</span> <span class="p">{</span> <span class="nb">test</span><span class="p">(</span><span class="mi">800</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="p">}.</span><span class="nf">pretty_print</span><span class="p">(</span><span class="ss">scale_bytes: </span><span class="kp">true</span><span class="p">,</span> <span class="ss">detailed_report: </span><span class="kp">false</span><span class="p">)</span>
</code></pre>
<p>Found when checking memory usage on RuboCop.</p> Ruby master - Bug #17030 (Closed): Enumerable#grep{_v} should be optimized for Regexphttps://bugs.ruby-lang.org/issues/170302020-07-13T20:26:50Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Currently,</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">array</span><span class="p">.</span><span class="nf">select</span> <span class="p">{</span> <span class="o">|</span><span class="n">e</span><span class="o">|</span> <span class="n">e</span><span class="p">.</span><span class="nf">match?</span><span class="p">(</span><span class="no">REGEXP</span><span class="p">)</span> <span class="p">}</span>
</code></pre>
<p>is about three times faster and six times more memory efficient than</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">array</span><span class="p">.</span><span class="nf">grep</span><span class="p">(</span><span class="no">REGEXP</span><span class="p">)</span>
</code></pre>
<p>This is because <code>grep</code> calls <code>Regexp#===</code>, which creates useless <code>MatchData</code>.</p> Ruby master - Bug #16996 (Closed): Hash should avoid doing unnecessary rehashhttps://bugs.ruby-lang.org/issues/169962020-06-27T08:20:32Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Pop quiz: Which is the fastest way to get a copy of a Hash <code>h</code>?</p>
<p>If, like me, you thought <code>h.dup</code> (of course, right?), you are actually wrong.</p>
<p>The fastest way is to call <code>h.merge</code>. Try it:</p>
<pre><code>require 'benchmark/ips'
lengths = 1..50
h = lengths.to_h { |i| ['x' * i, nil] }
Benchmark.ips do |x|
x.report("dup") { h.dup }
x.report("merge") { h.merge }
end
</code></pre>
<p>I get</p>
<pre><code>Calculating -------------------------------------
dup 259.233k (± 9.2%) i/s - 1.285M in 5.013445s
merge 944.095k (± 8.2%) i/s - 4.693M in 5.005315s
</code></pre>
<p>Yup, it's <em>3.5x faster</em> with this example!!</p>
<p>Why? Because <code>Hash#dup</code> does a rehash, and <code>merge</code> does not.</p>
<p>Pop quiz 2: which methods of <code>Hash</code> that produce a new hash do a rehash?</p>
<p>Answer: it depends on the method and on the Ruby version</p>
<pre><code>
+---------------------------------+------+-----+-----+-----+-----+-----+-----+-----+-----+
| Does this rehash? | head | 2.7 | 2.6 | 2.5 | 2.4 | 2.3 | 2.2 | 2.1 | 2.0 |
+---------------------------------+------+-----+-----+-----+-----+-----+-----+-----+-----+
| h.dup / clone | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
+---------------------------------+------+-----+-----+-----+-----+-----+-----+-----+-----+
| h.select{true} / reject{false} | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
+---------------------------------+------+-----+-----+-----+-----+-----+-----+-----+-----+
| h.select!{true} / reject!{false}| Ø | Ø | Ø | Ø | Ø | Ø | Ø | Ø | Ø |
+---------------------------------+------+-----+-----+-----+-----+-----+-----+-----+-----+
| sub_h.to_h | Ø | Ø | Ø | Ø | Ø | Ø | Ø | Ø | Ø |
+---------------------------------+------+-----+-----+-----+-----+-----+-----+-----+-----+
| h.merge({}) | Ø | Ø | Ø | Ø | Yes | Yes | Yes | Yes | Yes |
+---------------------------------+------+-----+-----+-----+-----+-----+-----+-----+-----+
| h.merge | Ø | Ø | Ø | n/a |
+---------------------------------+------+-----+-----+-----+-----+-----+-----+-----+-----+
| h.transform_values(&:itself) | Ø | Ø | Yes | Yes | Yes | n/a |
+---------------------------------+------+-----+-----+-----+-----+-----+-----+-----+-----+
(where `sub_h = Class.new(Hash).replace(h)`, Ø = no rehash)
</code></pre>
<p>So in Ruby head, doing <code>h.merge({})</code> or even <code>h.transform_values(&:itself)</code> will be much faster than <code>h.dup</code> (but slower in Ruby 2.4) (*)</p>
<p>Notice that <code>select</code> rehashes, but <code>select!</code> doesn't, so the fastest way to do a <code>select</code> in Ruby is... not to call select and instead to actually do a <code>merge.select!</code>! (*)</p>
<p>*: on hashes with non-negligible hash functions</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">Hash</span>
<span class="k">def</span> <span class="nf">fast_select</span><span class="p">(</span><span class="o">&</span><span class="n">block</span><span class="p">)</span>
<span class="n">merge</span><span class="p">.</span><span class="nf">select!</span><span class="p">(</span><span class="o">&</span><span class="n">block</span><span class="p">)</span> <span class="c1"># don't call dup because it's slow</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="no">Benchmark</span><span class="p">.</span><span class="nf">ips</span> <span class="k">do</span> <span class="o">|</span><span class="n">x</span><span class="o">|</span>
<span class="n">x</span><span class="p">.</span><span class="nf">report</span><span class="p">(</span><span class="s2">"select"</span><span class="p">)</span> <span class="p">{</span> <span class="n">h</span><span class="p">.</span><span class="nf">select</span><span class="p">{</span><span class="kp">true</span><span class="p">}</span> <span class="p">}</span>
<span class="n">x</span><span class="p">.</span><span class="nf">report</span><span class="p">(</span><span class="s2">"fast_select"</span><span class="p">)</span> <span class="p">{</span> <span class="n">h</span><span class="p">.</span><span class="nf">fast_select</span><span class="p">{</span><span class="kp">true</span><span class="p">}</span> <span class="p">}</span>
<span class="k">end</span>
</code></pre>
<p>On my test case above, <code>fast_select</code> is <em>2.5x faster</em> than <code>select</code>. <code>fast_select</code> will always return exactly the same result (unless the receiver needed a rehash).</p>
<p>Pop quiz 3: Is this a bug or a feature?</p>
<p>It should be clear that no feature of Ruby should be re-implementable in Ruby with a 3.5x / 2.5x speed gain, so many would think "of course it's a bug".</p>
<p>Well, <a href="https://bugs.ruby-lang.org/issues/16121" class="external">https://bugs.ruby-lang.org/issues/16121</a> seems to think that <code>Hash#dup</code>'s rehash is a feature...<br>
Why?<br>
Because there is actually a test that <code>dup</code> does a rehash<br>
Why?<br>
Because a test of <code>Set</code> was failing otherwise!<br>
Commit: <a href="https://github.com/ruby/ruby/commit/a34a3c2caae4c1fbd" class="external">https://github.com/ruby/ruby/commit/a34a3c2caae4c1fbd</a><br>
Short discussion: <a href="http://blade.nagaokaut.ac.jp/cgi-bin/vframe.rb/ruby/ruby-core/48040?47945-48527" class="external">http://blade.nagaokaut.ac.jp/cgi-bin/vframe.rb/ruby/ruby-core/48040?47945-48527</a><br>
Actual test: <a href="https://github.com/ruby/ruby/blob/master/test/test_set.rb#L621-L625" class="external">https://github.com/ruby/ruby/blob/master/test/test_set.rb#L621-L625</a><br>
Why?<br>
This test construct a <code>Set</code> that needs to be rehashed (by mutating an element of the set after it is added), and then checks that <code>rehash_me == rehash_me.clone</code>.<br>
That test is bogus. It passes for obscure and undocumented reasons, and <code>rehash_me.clone == rehash_me</code> doesn't pass.<br>
Today, it is official that sets with elements that are later mutated must be <code>Set#reset</code>, so it is official that this should not be relied upon.</p>
<p>Probably more clear is the case of <code>select/reject</code> (but I didn't check for failing test), and even more clear that <code>merge</code> changed in Ruby 2.5 and <code>transform_values</code> in 2.7, but not a single <code>NEWS</code> file mentions the word "rehash".</p>
<p>My conclusion is that Hash should avoid doing an unnecessary rehash: <code>dup</code>/<code>clone</code>/<code>select</code>/<code>reject</code>. We probably should add a reminder in the <code>NEWS</code> that if anyone mutates a key of a Hash, or an element of a Set and does not call <code>rehash</code>/<code>reset</code>, improper behavior should be expected.</p>
<p>Let's make <code>Hash#dup/clone/select/reject</code> fast please.</p>
<p>Any objection?</p> Ruby master - Bug #16281 (Closed): `irb -w` issues warninghttps://bugs.ruby-lang.org/issues/162812019-10-25T20:39:07Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<pre><code>$ irb -w
.rvm/rubies/ruby-head/lib/ruby/2.7.0/reline.rb:322: warning: instance variable @ambiguous_width not initialized
</code></pre>
<p>(Since f13db4adde532)</p> Ruby master - Bug #15731 (Closed): Wrong evaluation of many keyword default arguments in 2.3 - 2.5https://bugs.ruby-lang.org/issues/157312019-03-27T17:53:16Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I don't know if it's worth fixing at this point, but we found a strange bug with evaluation of default keyword arguments when there are many of them (more than 32).</p>
<pre><code>def foo(
k0: puts(0), k1: puts(1), k2: puts(2), k3: puts(3), k4: puts(4),
k5: puts(5), k6: puts(6), k7: puts(7), k8: puts(8), k9: puts(9),
k10: puts(10), k11: puts(11), k12: puts(12), k13: puts(13), k14: puts(14),
k15: puts(15), k16: puts(16), k17: puts(17), k18: puts(18), k19: puts(19),
k20: puts(20), k21: puts(21), k22: puts(22), k23: puts(23), k24: puts(24),
k25: puts(25), k26: puts(26), k27: puts(27), k28: puts(28), k29: puts(29),
k30: puts(30), k31: puts(31), k32: puts(32), k33: puts(33)
)
k33
end
puts "No params:"
foo # Should print 1 to 33
puts "Only k33 param:"
foo(k33: 1) # Should print 1 to 32
puts "Only k32 and k33 params:"
r = foo(k32: 1, k33: 1) # Should print 1 to 31 and return 1
puts "Result: #{r.inspect}"
</code></pre>
<p>Ruby 2.4:<br>
last case is wrong. It prints 1 to 33 instead of 1 to 31 and returns <code>nil</code> instead of 1.</p>
<p>Ruby 2.5:<br>
same result for last case<br>
first two cases evaluates the default exactly the wrong parameters: those that are given and not for those not given. So it prints nothing and 33 respectively, instead of 1 to 33 and 1 to 32!</p>
<p>Ruby 2.6:<br>
results are ok</p>
<p>This strange behavior disappears with fewer keyword arguments.</p> Ruby master - Bug #15718 (Closed): YAML raises error when dumping strings with UTF32 encodinghttps://bugs.ruby-lang.org/issues/157182019-03-20T20:21:55Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<pre><code class="shell syntaxhl" data-language="shell">ruby <span class="nt">-r</span> yaml <span class="nt">-e</span> <span class="s2">"p YAML.dump( ''.force_encoding('UTF-32LE') )"</span>
Traceback <span class="o">(</span>most recent call last<span class="o">)</span>:
4: from <span class="nt">-e</span>:1:in <span class="sb">`</span><main><span class="s1">'
3: from /Users/work/.rvm/rubies/ruby-2.6.1/lib/ruby/2.6.0/psych.rb:513:in `dump'</span>
2: from /Users/work/.rvm/rubies/ruby-2.6.1/lib/ruby/2.6.0/psych/visitors/yaml_tree.rb:118:in <span class="sb">`</span>push<span class="s1">'
1: from /Users/work/.rvm/rubies/ruby-2.6.1/lib/ruby/2.6.0/psych/visitors/yaml_tree.rb:136:in `accept'</span>
/Users/work/.rvm/rubies/ruby-2.6.1/lib/ruby/2.6.0/psych/visitors/yaml_tree.rb:298:in <span class="sb">`</span>visit_String<span class="s1">': incompatible encoding regexp match (US-ASCII regexp with UTF-32LE string) (Encoding::CompatibilityError)
</span></code></pre>
<p>Surprisingly, this works in Ruby 2.4.x, but not in 2.2, 2.3, 2.5 nor 2.6!</p> Ruby master - Bug #15613 (Closed): Enumerator::Chain#each doesn't relay block signaturehttps://bugs.ruby-lang.org/issues/156132019-02-20T04:29:41Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Currently, the block given when iterating on the components of a <code>Enumerator::Chain</code> always have arity of -1 and <code>lambda?</code> is always <code>false</code>:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">Foo</span>
<span class="kp">include</span> <span class="no">Enumerable</span>
<span class="k">def</span> <span class="nf">each</span><span class="p">(</span><span class="o">&</span><span class="n">block</span><span class="p">)</span>
<span class="k">return</span> <span class="n">to_enum</span> <span class="k">unless</span> <span class="n">block</span>
<span class="nb">p</span> <span class="n">block</span><span class="p">.</span><span class="nf">arity</span><span class="p">,</span> <span class="n">block</span><span class="p">.</span><span class="nf">lambda?</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">foo</span> <span class="o">=</span> <span class="no">Foo</span><span class="p">.</span><span class="nf">new</span>
<span class="n">foo</span><span class="p">.</span><span class="nf">each</span><span class="p">(</span><span class="o">&-></span><span class="p">{})</span> <span class="c1"># => 0, true</span>
<span class="n">foo</span><span class="p">.</span><span class="nf">each</span><span class="p">.</span><span class="nf">each</span><span class="p">(</span><span class="o">&-></span><span class="p">{})</span> <span class="c1"># => 0, true</span>
<span class="n">foo</span><span class="p">.</span><span class="nf">chain</span><span class="p">.</span><span class="nf">each</span><span class="p">(</span><span class="o">&-></span><span class="p">{})</span> <span class="c1"># => -1, false. Would ideally be 0, true</span>
</code></pre>
<p>It would be preferable if the block information wasn't lost.</p> Ruby master - Bug #15376 (Closed): Default gems: how will it work exactly?https://bugs.ruby-lang.org/issues/153762018-12-04T06:38:35Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Some standard libraries will be gemified in Ruby 2.6+.</p>
<ol>
<li>
<p>I believe we need to provide documentation for this. The NEWS file doesn't have much at all. The respective READMEs also have no relevant information and are misleading (see <a href="https://github.com/ruby/ostruct/pull/6" class="external">https://github.com/ruby/ostruct/pull/6</a>). I'll be glad to write an initial draft if need be, with the answers to the following questions...</p>
</li>
<li>
<p>Can we play with this right now? Maybe publishing prelease versions of these libraries?</p>
</li>
<li>
<p>Has this been tested with <code>Gemfile</code> and <code>gemspec</code>, i.e. it will be possible to add a specification for one of these?</p>
</li>
<li>
<p>What is supposed to happen if one does <code>gem install ostruct</code> in Ruby 2.5 (with current bundler, and with future bundler)?</p>
</li>
<li>
<p>Will it be possible to use these in <code>Gemfile</code>s even with older Ruby (but recent <code>bundler</code>), so one could say <code>gem 'ostruct'</code> in a Gemfile and run <code>bundle install</code> in Ruby 2.5 without things exploding?</p>
</li>
<li>
<p>Depending on 4/5, shouldn't we specify a <code> required_rubygems_version</code> and/or <code> required_ruby_version</code> in the gemspecs?</p>
</li>
</ol> Ruby master - Bug #15332 (Closed): coverage and InstructionSequence regressionhttps://bugs.ruby-lang.org/issues/153322018-11-22T23:31:26Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>With the current head:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"> <span class="nb">require</span> <span class="s1">'coverage'</span>
<span class="no">Coverage</span><span class="p">.</span><span class="nf">start</span>
<span class="no">RubyVM</span><span class="o">::</span><span class="no">InstructionSequence</span><span class="p">.</span><span class="nf">compile</span><span class="p">(</span><span class="s2">"puts 'hi'"</span><span class="p">,</span> <span class="s1">'hello_world.rb'</span><span class="p">).</span><span class="nf">eval</span>
<span class="no">Coverage</span><span class="p">.</span><span class="nf">result</span> <span class="c1"># => {}, should be {'hello_world.rb' => [1]}</span>
</code></pre>
<p>This is not intended, right?</p> Ruby master - Bug #15206 (Closed): require_relative in std_libhttps://bugs.ruby-lang.org/issues/152062018-10-06T03:17:08Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I noticed that there are some <code>require</code> for internal files in <code>lib/</code>. Ideally, they would be using <code>require_relative</code> instead. This is faster and more explicit.</p>
<p>Note: <code>require_relative</code> had a potential issue with symlinks that was fixed in 2.5, so libraries that might be loaded from earlier Ruby, like <code>rubygems</code>, can not yet be updated.</p>
<p>I've <a href="https://github.com/ruby/ruby/pull/1976" class="external">created a PR</a> and would like to know if there are comments / objections / things I'm missing.</p> Ruby master - Bug #15078 (Closed): Hash splat of empty hash should not create a positional argument.https://bugs.ruby-lang.org/issues/150782018-09-05T16:22:45Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Looks like <a class="issue tracker-1 status-5 priority-4 priority-default closed" title="Bug: Splat with empty keyword args gives unexpected results (Closed)" href="https://bugs.ruby-lang.org/issues/10856">#10856</a> is not completely fixed, but I can't reopen it</p>
<pre><code>def foo(*args); args; end
foo(**{}) # => []
foo(**Hash.new) # => [{}], should be []
</code></pre> Ruby master - Bug #14674 (Closed): New mismatched indentations warnings?https://bugs.ruby-lang.org/issues/146742018-04-10T17:43:28Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I recently got a failure in my test suite because ruby head warns of indentation it considers mismatched:</p>
<pre><code>$ ruby -w -e "
case
when :foo
end
"
-e:3: warning: mismatched indentations at 'when' with 'case' at 2
</code></pre>
<p>I hope this is not intentional and will be fixed.</p> Ruby master - Bug #14201 (Closed): Regression due to over optimization of hash splathttps://bugs.ruby-lang.org/issues/142012017-12-18T20:27:47Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>The following doesn't print anything nor raise anything in 2.5.0-rc1 or trunk:</p>
<pre><code>$ ruby -e "{**puts('hello')}; 42"
</code></pre>
<p>It should be the same as in Ruby 2.0-2.4:</p>
<pre><code>hello
-e:1:in `<main>': no implicit conversion of nil into Hash (TypeError)
</code></pre>
<p>Note: If you try to use the hash (e.g. passing as argument, storing in variable), then the correct behavior takes place. Found this bug through DeepCover's test suite.</p> Ruby master - Bug #14057 (Closed): TracePoint#enable and disable should not yield argumentshttps://bugs.ruby-lang.org/issues/140572017-10-26T06:54:53Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>While working on RubySpecs with Atul Bhosale, we discovered that <code>TracePoint#enable</code> and <code>#disable</code> yield <code>nil</code> instead of not yielding any argument.</p>
<p>This is mostly harmless as we usually use blocks, but it could create issues for lambdas/methods, for example:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">handle_trace</span><span class="p">;</span> <span class="k">end</span>
<span class="no">TracePoint</span><span class="p">.</span><span class="nf">new</span><span class="p">{}.</span><span class="nf">enable</span><span class="p">(</span><span class="o">&</span><span class="nb">method</span><span class="p">(</span><span class="ss">:handle_trace</span><span class="p">))</span> <span class="c1"># => ArgumentError: wrong number of arguments (given 1, expected 0)</span>
</code></pre>
<p>I'm fixing in trunk, would be nice to backport.</p> Ruby master - Bug #14031 (Closed): WeakRef example misleading and wronghttps://bugs.ruby-lang.org/issues/140312017-10-19T02:43:08Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I just noticed that the second part of the doc of <code>WeakRef</code> is misleading and later plainly wrong.</p>
<p>I'm talking about the example with <code>WeakHash</code> in<br>
<a href="https://ruby-doc.org/stdlib-2.4.0/libdoc/weakref/rdoc/WeakRef.html" class="external">https://ruby-doc.org/stdlib-2.4.0/libdoc/weakref/rdoc/WeakRef.html</a></p>
<p>The example shows</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">GC</span><span class="p">.</span><span class="nf">start</span>
<span class="n">c</span><span class="p">[</span><span class="s1">'foo'</span><span class="p">]</span> <span class="c1">#=> nil</span>
<span class="n">c</span><span class="p">[</span><span class="s1">'baz'</span><span class="p">]</span> <span class="c1">#=> nil</span>
<span class="n">c</span><span class="p">[</span><span class="s1">'qux'</span><span class="p">]</span> <span class="c1">#=> nil</span>
</code></pre>
<p>This is very <em>misleading</em>, since even before the GC that would be also the case, because <code>WeakHash</code> didn't redefine the lookup, and that <code>WeakHash.new('foo').eql?('foo')</code> is always <code>false</code>.</p>
<p>The doc goes on with:<br>
"You can see the local variable <code>omg</code> stayed, although its reference in our hash object was garbage collected, along with the rest of the keys and values."</p>
<p>That is <em>wrong</em>. The reference in our hash object was not garbage collected, since <code>omg</code> held on to it. This can be proven with <code>c.values.last # => 'lol'</code>.</p>
<p>My opinion is that fixing this example isn't worth it, and that even fixed it wouldn't add anything to the first simple example on WeakRef. In it's current form, it is worse dans not having it. Unless there are objections, I'll simply remove it.</p> Ruby master - Bug #14015 (Closed): Enumerable & Hash yielding arityhttps://bugs.ruby-lang.org/issues/140152017-10-14T20:19:18Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>The subtle difference between <code>yield 1, 2</code> and <code>yield [1, 2]</code> has always confused me.</p>
<p>Today I wanted to pass a method to Hash#flat_map and realized how it's even more confusing than I thought.</p>
<p>I assumed that <code>Hash#each</code> was calling <code>yield key, value</code>. But somehow it's not that simple:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="p">{</span><span class="ss">a: </span><span class="mi">1</span><span class="p">}.</span><span class="nf">map</span><span class="p">(</span><span class="o">&-></span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">value</span><span class="p">){})</span> <span class="c1"># => [nil]</span>
<span class="p">{</span><span class="ss">a: </span><span class="mi">1</span><span class="p">}.</span><span class="nf">flat_map</span><span class="p">(</span><span class="o">&-></span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">value</span><span class="p">){})</span> <span class="c1">#=> ArgumentError: wrong number of arguments (given 1, expected 2)</span>
</code></pre>
<p>What blows my mind, is that a custom method <code>each</code> that does <code>yield a, 1</code> has different result!</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="o"><<</span> <span class="n">o</span> <span class="o">=</span> <span class="no">Object</span><span class="p">.</span><span class="nf">new</span>
<span class="kp">include</span> <span class="no">Enumerable</span>
<span class="k">def</span> <span class="nf">each</span>
<span class="k">yield</span> <span class="ss">:a</span><span class="p">,</span> <span class="mi">1</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">o</span><span class="p">.</span><span class="nf">map</span><span class="p">(</span><span class="o">&-></span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">value</span><span class="p">){})</span> <span class="c1"># => [nil]</span>
<span class="n">o</span><span class="p">.</span><span class="nf">flat_map</span><span class="p">(</span><span class="o">&-></span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">value</span><span class="p">){})</span> <span class="c1"># => [nil] does not raise!!</span>
</code></pre>
<p>I don't even know how that's possible, since Hash doesn't have a specialized <code>flat_map</code> method...</p>
<p>Here's a list of methods that accept a lambda of arity 2 (as I would expect)<br>
For Hash<br>
each, any?, map, select, reject,<br>
For a custom yield<br>
each, any?, map, count, find_index, flat_map, all?, one?, none?, take_while, uniq</p>
<p>These two lists have <code>each</code>, <code>map</code> and <code>any?</code> in common. Others work in one flavor, not the other. Many require arity 1: find, sort_by, grep, grep_v, count, detect, find_index, find_all, ...</p>
<p>To make things even more impossible, <code>Hash#map</code> has been working with arity 2 since Ruby 2.4 only.</p>
<p>Finally, <code>Hash#each</code> changes the expected arity of <code>select</code>, <code>reject</code>, and <code>any?</code>, but not of <code>map</code>:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"> <span class="p">{</span><span class="ss">a: </span><span class="mi">1</span><span class="p">}</span> <span class="p">.</span><span class="nf">select</span><span class="p">(</span><span class="o">&-></span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">){})</span> <span class="c1"># => {}</span>
<span class="p">{</span><span class="ss">a: </span><span class="mi">1</span><span class="p">}.</span><span class="nf">each</span><span class="p">.</span><span class="nf">select</span><span class="p">(</span><span class="o">&-></span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">){})</span> <span class="c1"># => wrong number of arguments (given 1, expected 2)</span>
</code></pre>
<p>Conclusion:</p>
<p>It seems more or less impossible to guess the expected arity of methods of Enumerable and of Hash, and they are not even consistent with one another. This makes these methods more or less unusable with lambdas.</p>
<p>While compatibility could be an issue, the fact that <code>Hash#map</code> has changed it's arity (I believe following <a href="https://bugs.ruby-lang.org/issues/13391" class="external">https://bugs.ruby-lang.org/issues/13391</a> ) makes me think that compatibility with the lesser used methods would be even less of a problem.</p>
<p>My personal wish: that the following methods be fixed to expect arity 2 for lambdas:</p>
<p>For both Hash & Enumerable:</p>
<ul>
<li>find, sort_by, grep, grep_v, detect, find_all, partition, group_by, min_by, max_by, minmax_by, reverse_each, drop_while, sum<br>
For Hash:</li>
<li>count, find_index, flat_map, all?, one?, none?, take_while, uniq<br>
For Enumerable:</li>
<li>select, reject</li>
</ul>
<p>Matz, what do you think?</p> Ruby master - Bug #14014 (Closed): NaN.finite?https://bugs.ruby-lang.org/issues/140142017-10-13T21:23:28Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Ruby gives contradictory answers for NaN:</p>
<pre><code>> (0/0.0).finite?
=> false
> Complex(0/0.0, 0).finite?
=> true
</code></pre>
<p>Note that <code>(0/0.0).infinite?</code> returns <code>nil</code>, so the float answer of <code>false</code> looks even more wrong.</p>
<p>The two solutions I see are either changing <code>Float#finite?</code> to return <code>true</code> for NaN, or to raise in both cases.</p>
<p>I'd lean towards raising in both cases, as NaN can not be said to be finite or infinite</p> Ruby master - Bug #13973 (Closed): super_method fails on some UnboundMethodshttps://bugs.ruby-lang.org/issues/139732017-10-05T02:01:33Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p><code>super_method</code> fails to go up the ancestry chain for methods that are only defined in included modules:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">module</span> <span class="nn">A</span>
<span class="k">def</span> <span class="nf">foo</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">module</span> <span class="nn">B</span>
<span class="k">def</span> <span class="nf">foo</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">class</span> <span class="nc">C</span>
<span class="kp">include</span> <span class="no">A</span>
<span class="kp">include</span> <span class="no">B</span>
<span class="k">end</span>
<span class="k">class</span> <span class="nc">D</span>
<span class="k">def</span> <span class="nf">foo</span>
<span class="k">end</span>
<span class="kp">include</span> <span class="no">A</span>
<span class="kp">include</span> <span class="no">B</span>
<span class="k">end</span>
<span class="no">C</span><span class="p">.</span><span class="nf">instance_method</span><span class="p">(</span><span class="ss">:foo</span><span class="p">)</span> <span class="c1"># => #<UnboundMethod: C(B)#foo> (ok)</span>
<span class="no">C</span><span class="p">.</span><span class="nf">instance_method</span><span class="p">(</span><span class="ss">:foo</span><span class="p">).</span><span class="nf">super_method</span> <span class="c1"># => nil (wrong, should be <UnboundMethod: <something>(A)#foo>)</span>
<span class="no">C</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">:foo</span><span class="p">).</span><span class="nf">super_method</span> <span class="c1"># => #<Method: Object(A)#foo> (ok)</span>
<span class="no">D</span><span class="p">.</span><span class="nf">instance_method</span><span class="p">(</span><span class="ss">:foo</span><span class="p">).</span><span class="nf">super_method</span> <span class="c1"># => #<UnboundMethod: Object(B)#foo> (ok)</span>
<span class="no">D</span><span class="p">.</span><span class="nf">instance_method</span><span class="p">(</span><span class="ss">:foo</span><span class="p">).</span><span class="nf">super_method</span><span class="p">.</span><span class="nf">super_method</span> <span class="c1"># => #<UnboundMethod: Object(A)#foo> (ok)</span>
</code></pre>
<p>Note that the results for C and D's super_method differ slightly, with one outputing "C(B)" and the other "Object(B)". I don't understand why "Object" shows anywhere in my example. I would have expected the output to be "D(B)" in the later case. Should I open a different issue for this?</p> Ruby master - Bug #11776 (Closed): dig and custom objectshttps://bugs.ruby-lang.org/issues/117762015-12-06T05:18:02Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Although currently undocumented and untested, it is possible to <code>dig</code> objects of any class that implements <code>dig</code>:</p>
<pre><code>class Foo
def dig(x, *)
40 + x
end
end
{hello: Foo.new}.dig(:hello, 2) # => 42
</code></pre>
<p>This seems actually quite nice to me.</p>
<p>Matz, could you confirm that this is part of the new feature? I'll fix the documentation and add some basic tests</p> Ruby master - Bug #10831 (Closed): Variable keyword arguments shouldn't create immortal symbolshttps://bugs.ruby-lang.org/issues/108312015-02-05T19:58:53Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Calling a method with keyword arguments will, sometimes, create immortal symbols.</p>
<p>The following tests should not fail:</p>
<pre><code>def test_kwarg_symbol_leak_no_rest
foo = -> (arg: 42) {}
assert_no_immortal_symbol_created("kwarg no rest") do |name|
assert_raise(ArgumentError) { foo.call(name.to_sym => 42) }
end
end
def test_kwarg_symbol_leak_with_rest
foo = -> (arg: 2, **options) {}
assert_no_immortal_symbol_created("kwarg with rest") do |name|
foo.call(name.to_sym => 42)
end
end
def test_kwarg_symbol_leak_just_rest
foo = -> (**options) {}
assert_no_immortal_symbol_created("kwarg just rest") do |name|
foo.call(name.to_sym => 42)
end
end
</code></pre>
<p>Note: the last one succeeds (because the hash is simply cloned internally), and is there for completeness.</p> Ruby master - Bug #10828 (Closed): send should not create immortal symbolshttps://bugs.ruby-lang.org/issues/108282015-02-04T19:01:50Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>While <code>public_send</code> is ok, <code>send</code> and <code>__send__</code> create immortal symbols when they shouldn't.</p> Ruby master - Bug #9660 (Closed): test/unit, minitest & bundlerhttps://bugs.ruby-lang.org/issues/96602014-03-21T19:15:10Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>test/unit now calls <code>gem 'minitest'</code>, but this will create regressions for anyone using <code>bundler</code>.</p>
<p>For example, create an empty <code>Gemfile</code> and try <code>bundle exec ruby -e "require 'test/unit'"</code></p>
<p>You get an error:</p>
<pre><code>.rvm/gems/ruby-head@global/gems/bundler-1.5.3/lib/bundler/rubygems_integration.rb:240:in `block in replace_gem': minitest is not part of the bundle. Add it to Gemfile. (Gem::LoadError)
</code></pre>
<p>See: <a href="https://github.com/ruby/ruby/commit/da61291a25faae95f33de6756b2eaa4804d5ef2b#commitcomment-5761129" class="external">https://github.com/ruby/ruby/commit/da61291a25faae95f33de6756b2eaa4804d5ef2b#commitcomment-5761129</a></p> Ruby master - Bug #9242 (Closed): Rdoc detection of aliaseshttps://bugs.ruby-lang.org/issues/92422013-12-12T04:46:38Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>The online doc appears to be making bad detection of aliases.</p>
<p>For example, Array#map and Array#collect are not marked as aliases (on either ruby-doc.org or docs.ruby-lang.org)</p>
<p>On the other hand, when aliases are detected, the generated method interface and the name of the method it is aliases to are always the same for both methods.</p>
<p>For example, the doc for Array#find_index says it is an alias to find_index and has interface showing index (again on both sites), e.g. <a href="http://docs.ruby-lang.org/en/2.0.0/Array.html#method-i-find_index" class="external">http://docs.ruby-lang.org/en/2.0.0/Array.html#method-i-find_index</a></p>
<p>It might also be a good idea to always have doc examples using both forms in case of aliases.</p> Ruby master - Bug #9048 (Closed): Remove legacy ±(binary) special cases.https://bugs.ruby-lang.org/issues/90482013-10-24T00:30:13Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Is there any reason not to get rid of the following special cases?</p>
<pre><code>'+(binary)'.to_sym # => :+ when expected :"+(binary)"
</code></pre>
<p>The following patch didn't reveal any failure in make test:</p>
<p>diff --git a/parse.y b/parse.y<br>
index 76fc9e7..6550235 100644<br>
--- a/parse.y<br>
+++ b/parse.y<br>
@@ -10045,8 +10045,6 @@ static const struct {<br>
} op_tbl[] = {<br>
{tDOT2, ".."},<br>
{tDOT3, "..."},</p>
<ul>
<li>{'+', "+(binary)"},</li>
<li>{'-', "-(binary)"},<br>
{tPOW, "<strong>"},<br>
{tDSTAR, "</strong>"},<br>
{tUPLUS, "+@"},<br>
diff --git a/test/ruby/test_m17n.rb b/test/ruby/test_m17n.rb<br>
index 7c37c8a..3ea346f 100644<br>
--- a/test/ruby/test_m17n.rb<br>
+++ b/test/ruby/test_m17n.rb<br>
@@ -1230,7 +1230,7 @@ class TestM17N < Test::Unit::TestCase</li>
</ul>
<p>def test_symbol_op<br>
ops = %w"</p>
<ul>
<li>
<pre><code> .. ... + - +(binary) -(binary) * / % ** +@ -@ | ^ & ! <=> > >= < <= ==
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> .. ... + - * / % ** +@ -@ | ^ & ! <=> > >= < <= ==
=== != =~ !~ ~ ! [] []= << >> :: `
</code></pre>
"<br>
ops.each do |op|</li>
</ul> Ruby master - Bug #8894 (Closed): Fixnum#quo returns wrong result when given a floathttps://bugs.ruby-lang.org/issues/88942013-09-11T13:07:36Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Fixnum#quo is buggy.</p>
<p>2.quo(2.0) # => Rational(2, 2)</p>
<ol>
<li>Should return a float, not a rational</li>
<li>Moreover, that rational is invalid as it is not reduced.</li>
</ol>
<p>Noticed by David MacMahon <a href="/issues/8883">[ruby-core:57121]</a></p> Ruby master - Bug #8841 (Closed): Module#included_modules and prepended moduleshttps://bugs.ruby-lang.org/issues/88412013-08-31T08:17:39Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>The documentation for Module#included_modules currently states "Returns the list of modules included in +mod+."</p>
<p>This was never perfectly accurate, as the list also contains modules included in +mod+'s ancestors.</p>
<p>It now also includes prepended modules.</p>
<p>This is consistent with <code>include?</code> that returns true for prepended modules, but not quite consistent with <code>included</code> that does not get called for prepended modules.</p>
<p>Matz, could you confirm that current behavior is what you want?</p>
<p>If so, we should fix the documentation of <code>include?</code> and <code>included_modules</code>.</p> Ruby master - Bug #8162 (Closed): Documentation for trust/taint lackinghttps://bugs.ruby-lang.org/issues/81622013-03-25T11:04:42Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>If would be good to make the documentation for {un}{trust|taint}{ed?} clearer. c.f. <a href="https://blade.ruby-lang.org/ruby-core/53679">[ruby-core:53679]</a></p> Ruby master - Bug #8161 (Closed): String#+ should inherit untrustednesshttps://bugs.ruby-lang.org/issues/81612013-03-25T11:02:41Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>As noted by Nikolai Weibull <a href="https://blade.ruby-lang.org/ruby-core/53679">[ruby-core:53679]</a>, String#+ doesn't maintain untrustedness.</p>
<pre><code>s = "foo".untrust
(s * 2).untrusted? # => true
(s + s).untrusted? # => false, should be true
(s + '').untrusted? # => false, should also be true
</code></pre> Ruby master - Bug #8045 (Closed): Object#singleton_methods incompatible with prependhttps://bugs.ruby-lang.org/issues/80452013-03-08T09:57:00Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Similar to <a class="issue tracker-1 status-5 priority-4 priority-default closed" title="Bug: Object#methods incompatible with prepend (Closed)" href="https://bugs.ruby-lang.org/issues/8044">#8044</a>, although implementation is independent:</p>
<pre><code>o=Object.new
def o.foo; end
o.singleton_methods(false) # => [:foo], ok
o.singleton_class.send :prepend, Enumerable
o.singleton_methods(false) # => [], should be [:foo]
</code></pre> Ruby master - Bug #8044 (Closed): Object#methods incompatible with prependhttps://bugs.ruby-lang.org/issues/80442013-03-08T09:49:35Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Object#methods incompatible with prepend:</p>
<pre><code>o = Object.new
def o.foo; end
o.methods(false) # => [:foo], ok
o.singleton_class.send :prepend, Enumerable
o.methods(false) # => [], should be [:foo]
</code></pre> Ruby master - Bug #8041 (Closed): Marshal incompatibility with prependhttps://bugs.ruby-lang.org/issues/80412013-03-08T08:13:21Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Marshal doesn't work for objects with prepended modules:</p>
<pre><code>o = Object.new
o.singleton_class.send :include, Enumerable
Marshal.load(Marshal.dump(o)) # => ok
o = Object.new
o.singleton_class.send :prepend, Enumerable
Marshal.load(Marshal.dump(o)) # => ArgumentError: Object does not refer to module
</code></pre>
<p>=end</p> Ruby master - Bug #7916 (Closed): Callback Module.used is not used...https://bugs.ruby-lang.org/issues/79162013-02-23T08:08:28Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Module.used was meant to be called when it is called with <code>using</code>, see r36596.</p>
<p>It's not called right now.</p> Ruby master - Bug #7780 (Closed): Marshal & YAML should deserialize only basic types by default.https://bugs.ruby-lang.org/issues/77802013-02-04T11:30:48Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>YAML is a wonderful, powerful and expressive format to serialize data in a human readable way.</p>
<p>It can be used, for example, to read and write nice configuration files, to store strings, numbers, dates & times in a hash.</p>
<p>YAML.load will, by default, instantiate any user class and set instance variables directly.</p>
<p>On the other hand, this can make apparently innocent code lead to major vulnerabilities, as was clearly illustrated by different exploits recently.</p>
<p>I feel YAML.load should, by default, be safe to use, for example by instantiating only known core classes.</p>
<p>The same can be said for Marshal, even though it would more rarely be used as a public interface to exchange data.</p>
<p>Maybe the following transition path could be taken:</p>
<ol>
<li>Have {YAML|Marshal}.load issue a warning (once) that next minor will only deserialize basic types.</li>
<li>Create {YAML|Marshal}.unsafe_load, which does the same thing as current <code>load</code>, without a warning of course.<br>
As these changes are compatible and extremely minor, I would like them to be considered for Ruby 2.0.0. They also make for a</li>
</ol>
<p>"Secure by default" is not a new concept.<br>
Rails 3.0 has XSS protection by default, for example. The fact that one needs to do extra processing like calling <code>raw</code> when that security needs to be bypassed makes XSS attacks less likely.<br>
I believe the typical use of Yaml.load is to load basic types.<br>
We should expect users to use the easiest solution, so that should be the safe way.<br>
If a tool makes the safe way of doing things the default, and makes it easy to do more complex deserializing (e.g. whitelisting some user classes), this can only lead to less vulnerabilities.</p>
<p>I hope nobody will take offence that I've tagged this issue as a "bug". The current behavior is as speced, but it can be argued that a design that is inherently insecure is a defect.</p> Ruby master - Bug #7765 (Closed): Proc#arity bug with optional argumenthttps://bugs.ruby-lang.org/issues/77652013-02-01T05:38:17Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>We have:</p>
<pre><code>Proc.new{|a, b, c, d, e|}.arity # => 5
</code></pre>
<p>Matz decided <a href="/issues/5694">[ruby-core:46515]</a> we also have:</p>
<pre><code>Proc.new{|a, b, c, d, e=0|}.arity # => 4
</code></pre>
<p>It looks like we currently have:</p>
<pre><code>Proc.new{|a, b=0, c, d, e|}.arity # => 1, should be same as above
</code></pre>
<p>Hopefully there won't be disagreement that this is a bug?</p>
<p>I'm asking in particular because there was a specific test committed by Yui to that effect. I hope this was just an oversight?</p>
<pre><code>assert_equal(0, proc{|x=0, y|}.arity) # Should be 1, not 0. test/ruby/test_proc.rb:67
</code></pre>
<p>My patch is ready and I will commit it unless there is objection.</p>
<p><a href="https://github.com/marcandre/ruby/compare/marcandre:trunk...marcandre:proc_curry" class="external">https://github.com/marcandre/ruby/compare/marcandre:trunk...marcandre:proc_curry</a></p> Ruby master - Bug #7757 (Closed): String#start_with? and end_with? should accept Regexphttps://bugs.ruby-lang.org/issues/77572013-01-31T01:22:26Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>As suggested by Ilya in <a class="issue tracker-1 status-5 priority-4 priority-default closed" title="Bug: String#start_with? and end_with? ignore arguments convertible to a String [PATCH] (Closed)" href="https://bugs.ruby-lang.org/issues/5536">#5536</a>, the following should work:</p>
<pre><code>"hello".start_with? /h/ # => true, not a TypeError
</code></pre> Ruby master - Bug #7755 (Closed): JSON::Generate#configure's argument conversionhttps://bugs.ruby-lang.org/issues/77552013-01-30T04:33:38Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I notice a tiny bug in ext/json/generator/generator.c:514</p>
<pre><code>tmp = rb_convert_type(opts, T_HASH, "Hash", "to_hash");
if (NIL_P(tmp)) tmp = rb_convert_type(opts, T_HASH, "Hash", "to_h");
if (NIL_P(tmp)) {
rb_raise(rb_eArgError, "opts has to be hash like or convertable into a hash");
}
opts = tmp;
</code></pre>
<p>Bug is that rb_convert_type never returns nil.</p>
<p>Either both rb_convert_type are changed to rb_check_convert_type, or these lines are simply replaced by:</p>
<pre><code>opts = rb_convert_type(opts, T_HASH, "Hash", "to_hash");
</code></pre>
<p>I'd recommend this last option, for consistency with the rest of MRI.</p> Ruby master - Bug #7728 (Closed): Range#bsearch on other Numerics?https://bugs.ruby-lang.org/issues/77282013-01-23T03:12:30Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Range#bsearch attempts to do something on generic Numeric classes.</p>
<p>I feel it is both useless and buggy:</p>
<pre><code>(Rational(-1,2)..Rational(9,4)).bsearch{|x| true} # => yields with 7/8 and 33/16
(Rational(-1,2)..Rational(9,4)).bsearch{|x| false} # => loops forever
(BigDecimal('0.5')..BigDecimal('2.25'))... # => same
</code></pre>
<p>I feel the current implementation (aside from the bugs) only makes sense on Integers.</p>
<p>Possible approaches:</p>
<ul>
<li>Rational</li>
</ul>
<ol>
<li>convert to float, or</li>
<li>bsearch accepts a "max iterations" parameter (which would be required for Rational), or</li>
<li>forbid altogether</li>
</ol>
<ul>
<li>BigDecimal</li>
</ul>
<ol>
<li>convert to float, or</li>
<li>look at the space of decimal numbers in the range without a higher precision than begin or end.</li>
</ol>
<p>Given the timeframe though, I recommend we raise a TypeError for both in 2.0.0 (or a NotImplemented if we decide what should be done).</p> Ruby master - Bug #7726 (Closed): bsearch should handle block result in a consistent wayhttps://bugs.ruby-lang.org/issues/77262013-01-22T18:52:35Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>The documentation states that the block of bsearch must<br>
return either true/false or a number.</p>
<p>If the block returns another object (other than nil), I feel that either</p>
<ol>
<li>It should be considered as 'truthy'</li>
<li>It should raise a TypeError</li>
</ol>
<p>Currently it does not raise an error and returns a result different than if <code>true</code> was passed:</p>
<p>(1..3).bsearch{ 'x' } == (1..3).bsearch{ true } # => false</p> Ruby master - Bug #7725 (Closed): bsearch should return enumerator when called without a blockhttps://bugs.ruby-lang.org/issues/77252013-01-22T18:48:44Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>bsearch should return enumerator when called without a block</p>
<p>This would allow, for example</p>
<p>values.bsearch.with_index{|val, index| val >= some_array[index]} # => a value</p>
<p>Otherwise, one must use zip/each_with_index and will get an array returned, not just the value seeked:</p>
<p>r = values.zip(some_array).bsearch{|val, other_val| val >= other_val}<br>
a_value = r.first</p> Ruby master - Bug #7724 (Closed): 6 bugs with Range#bsearch over floatshttps://bugs.ruby-lang.org/issues/77242013-01-22T18:47:35Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Take the following code, with from, to and search all Integer or all Float:</p>
<p>(from...to).bsearch{|f| f >= search}</p>
<p>I expected it to:<br>
0) never yield and return nil if range is empty, i.e. from >= to ("trivial test")</p>
<ol>
<li>never yield more than 65 times for floats<br>
or Math.log(to-from, 2)+1 for Integer ("log test")</li>
<li>return search if from <= search < to, nil otherwise ("coverage test")</li>
<li>never yield the same <code>f</code> ("uniqueness test")</li>
<li>if range is exclusive, never yield <code>to</code> nor return <code>to</code>; if range is inclusive and block returns false always yield <code>to</code> ("end of range test")</li>
<li>never yield a number < from or > to ("out of range test")</li>
</ol>
<p>These conditions are all respected for Integers but all can be broken for Floats<br>
Test 0, 1, 3, 4 & 5 fail even for small ordinary float values, while test 2 requires some larger floats, say 1e100 to fail.<br>
For example bsearch can yield over 2000 times (instead of at most 65).</p>
<p>These tests and a correct Ruby implementation of bsearch can be found here: <a href="https://github.com/marcandre/backports/compare/marcandre:master...marcandre:bsearch" class="external">https://github.com/marcandre/backports/compare/marcandre:master...marcandre:bsearch</a><br>
My implementation also passes the MRI tests.</p> Ruby master - Bug #7715 (Closed): Lazy enumerators should want to stay lazy.https://bugs.ruby-lang.org/issues/77152013-01-19T02:33:26Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I'm just waking up to the fact that many methods turn a lazy enumerator in a non-lazy one.</p>
<p>Here's an example from Benoit Daloze in <a href="/issues/6261">[ruby-core:44151]</a>:</p>
<p>lines = File.foreach('a_very_large_file').lazy<br>
.select {|line| line.length < 10 }<br>
.map {|line| line.chomp!; line }<br>
.each_slice(3)<br>
.map {|lines| lines.join(';').downcase }<br>
.take_while {|line| line.length > 20 }</p>
<p>That code will produce the right result but <em>will read the whole file</em>, which is not what is desired</p>
<p>Indeed, <code>each_slice</code> currently does not return a lazy enumerator :-(</p>
<p>To make the above code as intended, one must call <code>.lazy</code> right after the <code>each_slice(3)</code>. I feel this is dangerous and counter intuitive.</p>
<p>Is there a valid reason for this behavior? Otherwise, I would like us to consider returning a lazy enumerator for the following methods:<br>
(when called without a block)<br>
each_with_object<br>
each_with_index<br>
each_slice<br>
each_entry<br>
each_cons<br>
(always)<br>
chunk<br>
slice_before</p>
<p>The arguments are:</p>
<ul>
<li>fail early (much easier to realize one needs to call a final <code>force</code>, <code>to_a</code> or <code>each</code> than realizing that a lazy enumerator chain isn't actually lazy)</li>
<li>easier to remember (every method normally returning an enumerator returns a lazy enumerator). basically this makes Lazy covariant</li>
<li>I'd expect that if you get lazy at some point, you typically want to remain lazy until the very end</li>
</ul> Ruby master - Bug #7706 (Closed): Lazy#zip should not call `lazy`https://bugs.ruby-lang.org/issues/77062013-01-17T03:27:36Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Current implementation of Lazy#zip has problems:</p>
<ol>
<li>
<p>calls <code>lazy</code> when this is not excepted, necessary nor documented. Any reason to not call <code>each</code> instead?</p>
</li>
<li>
<p>calls <code>lazy</code> without checking previously for type:</p>
<p>[1].lazy.zip(42) # =>NoMethodError: undefined method `lazy' for 42:Fixnum</p>
<a name="expected-same-as-1zip42-ie-a-TypeError"></a>
<h1 >expected same as [1].zip(42), i.e. a TypeError<a href="#expected-same-as-1zip42-ie-a-TypeError" class="wiki-anchor">¶</a></h1>
</li>
<li>
<p>inefficient in the case where all arguments are arrays</p>
</li>
</ol>
<p>I'll address these when I get a chance. I don't understand why <code>lazy</code> is called instead of <code>each</code> though. Anyone?</p> Ruby master - Bug #7696 (Closed): Lazy enumerators with state can't be rewoundhttps://bugs.ruby-lang.org/issues/76962013-01-15T06:45:46Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>The 4 lazy enumerators requiring internal state, i.e. {take|drop}{_while}, don't work as expected after a couple <code>next</code> and a call to <code>rewind</code>.</p>
<p>For example:</p>
<pre><code>e=(1..42).lazy.take(2)
e.next # => 1
e.next # => 2
e.rewind
e.next # => 1
e.next # => StopIteration: iteration reached an end, expected 2
</code></pre>
<p>This is related to <a class="issue tracker-1 status-5 priority-4 priority-default closed" title="Bug: 3 bugs with Lazy enumerators with state (Closed)" href="https://bugs.ruby-lang.org/issues/7691">#7691</a>; the current API does not give an easy way to handle state.</p>
<p>Either there's a dedicated callback to rewind, or data must be attached to the yielder.</p> Ruby master - Bug #7692 (Closed): Enumerator::Lazy#drop_while and take_while should require a block.https://bugs.ruby-lang.org/issues/76922013-01-14T16:33:07Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Enumerator::Lazy#drop_while and take_while should require a block.</p>
<p>Currently:</p>
<pre><code>[1].lazy.drop_while.force # => LocalJumpError: no block given
[1].lazy.take_while.force # => LocalJumpError: no block given
</code></pre>
<p>After patch, these will raise an ArgumentError "tried to call lazy drop_while without a block"</p> Ruby master - Bug #7691 (Closed): 3 bugs with Lazy enumerators with statehttps://bugs.ruby-lang.org/issues/76912013-01-14T14:53:31Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I found the following 3 bugs with Lazy#drop, drop_while and zip:</p>
<pre><code>drop = (1..4).lazy.drop(2)
drop.to_a # => [3, 4]
drop.to_a # => [1, 2, 3, 4], should be same as above
drop_while = (1..4).lazy.drop_while(&:odd?)
drop_while.to_a # => [2, 3, 4]
drop_while.to_a # => [1, 2, 3, 4], should be same as above
zip = (1..2).lazy.zip([3, 4]) # or (3..4)
zip.to_a # => [[1, 3], [2, 4]]
zip.to_a # => [[1, nil], [2, nil]] should be same as above
</code></pre>
<p>I found them when writing a Ruby implementation of Enumerator::Lazy.</p>
<p>My implementation created the same bug with #take as described in <a href="https://bugs.ruby-lang.org/issues/6428" class="external">https://bugs.ruby-lang.org/issues/6428</a>.</p>
<p>This made me realize that the api of Lazy.new makes it near impossible to write most lazy enumerators requiring a state, as there is no general way to reset that state.</p>
<p>When looking at my code, I used a state for drop, drop_while and zip. A quick verification showed me that the MRI implementation also has the same bugs!gene</p>
<p>So the meta question is: should there not be a general way to initialize the state of the lazy enum?</p> Ruby master - Bug #7690 (Closed): Enumerable::Lazy#flat_map should not call eachhttps://bugs.ruby-lang.org/issues/76902013-01-13T11:30:38Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I would expect that</p>
<pre><code>array.flat_map{...} == array.lazy.flat_map{...}.force
</code></pre>
<p>This is not always the case:</p>
<pre><code>[1].flat_map{|i| {i => i} } # => [{1 => 1}], ok
[1].lazy.flat_map{|i| {i => i} }.force # => [[1, 1]], expected [{1 => 1}]
</code></pre>
<p>Note that Matz confirmed that it is acceptable to return straight objects instead of arrays for flat_map <a href="/issues/6155">[ruby-core:43365]</a></p>
<p>It looks like this was intended for nested lazy enumerators:</p>
<pre><code>[1].lazy.flat_map{|i| [i].lazy }.force # => [1]
</code></pre>
<p>I don't think that's the correct result, and it is different from a straight flat_map:</p>
<pre><code>[1].flat_map{|i| [i].lazy } # => [#<Enumerator::Lazy: [1]>]
</code></pre>
<p>This is caused by Lazy#flat_map calls each (while Enumerable#flat_map only looks for Arrays/object responding to to_ary).</p> Ruby master - Bug #7248 (Closed): Shouldn't Enumerator::Lazy.new be private?https://bugs.ruby-lang.org/issues/72482012-10-31T13:23:13Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Is there a reason why Enumerator::Lazy.new is not private?</p>
<p>Lazy enumerators should be created with <code>Enumerable#lazy</code>. Moreover, there is no doc, and it can give unexpected results too.</p> Ruby master - Bug #6658 (Closed): Module#ancestors & prependhttps://bugs.ruby-lang.org/issues/66582012-06-28T03:16:47Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Wouldn't it be best if <code>Module#ancestors</code> returned the modules & classes in the order they will be looked at?</p>
<p>Currently:</p>
<pre><code>module M; end
class C; prepend M; end
C.ancestors # => [C, M, Class, Object, Kernel, BasicObject]
# even though actual lookup order is [M, C, Class, Object, Kernel, BasicObject]
</code></pre> Ruby master - Bug #6120 (Closed): Float and BigDecimal bug in remainder in corner caseshttps://bugs.ruby-lang.org/issues/61202012-03-07T14:51:41Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Currently:</p>
<pre><code>4.2.remainder(+Float::INFINITY) # => 4.2, ok
4.2.remainder(-Float::INFINITY) # => NaN, should be 4.2
# (same with all signs reversed)
</code></pre>
<p>Reasons the remainder should be 4.2 and not NaN:</p>
<ol>
<li>foo.remainder(bar) == foo.remainder(-bar)</li>
<li>foo.remainder(bar) == foo when bar.abs > foo.abs</li>
</ol>
<p>Similarly:<br>
require 'bigdecimal'<br>
bd = BigDecimal.new("4.2")<br>
bd.remainder(BigDecimal.new("+Infinity")) # => NaN, should be bd<br>
bd.remainder(BigDecimal.new("-Infinity")) # => NaN, should be bd<br>
# (same with all signs reverse)</p>
<p>Reasons: same as float.</p>
<p>Finally:<br>
bd = BigDecimal.new("4.2")<br>
bd.modulo(BigDecimal.new("0")) # => ZeroDivisionError, probably ok?<br>
bd.remainder(BigDecimal.new("0")) # => NaN, should be probably raise a ZeroDivisionError?</p>
<p>Like in <a class="issue tracker-4 status-5 priority-4 priority-default closed" title="Backport: Float#% bug in cornercases (Closed)" href="https://bugs.ruby-lang.org/issues/6044">#6044</a>, this could be decided either way, as long as there is consistency. Anyone prefer NaN to raising a ZeroDivisionError?</p> Ruby master - Bug #6087 (Closed): How should inherited methods deal with return values of their o...https://bugs.ruby-lang.org/issues/60872012-02-26T06:02:37Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Just noticed that we still don't have a consistent way to handle return values:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">A</span> <span class="o"><</span> <span class="no">Array</span>
<span class="k">end</span>
<span class="n">a</span> <span class="o">=</span> <span class="no">A</span><span class="p">.</span><span class="nf">new</span>
<span class="n">a</span><span class="p">.</span><span class="nf">flatten</span><span class="p">.</span><span class="nf">class</span> <span class="c1"># => A</span>
<span class="n">a</span><span class="p">.</span><span class="nf">rotate</span><span class="p">.</span><span class="nf">class</span> <span class="c1"># => Array</span>
<span class="p">(</span><span class="n">a</span> <span class="o">*</span> <span class="mi">2</span><span class="p">).</span><span class="nf">class</span> <span class="c1"># => A</span>
<span class="p">(</span><span class="n">a</span> <span class="o">+</span> <span class="n">a</span><span class="p">).</span><span class="nf">class</span> <span class="c1"># => Array</span>
</code></pre>
<p>Some methods are even inconsistent depending on their arguments:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">a</span><span class="p">.</span><span class="nf">slice!</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">).</span><span class="nf">class</span> <span class="c1"># => A</span>
<span class="n">a</span><span class="p">.</span><span class="nf">slice!</span><span class="p">(</span><span class="mi">0</span><span class="o">..</span><span class="mi">0</span><span class="p">).</span><span class="nf">class</span> <span class="c1"># => A</span>
<span class="n">a</span><span class="p">.</span><span class="nf">slice!</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">).</span><span class="nf">class</span> <span class="c1"># => Array</span>
<span class="n">a</span><span class="p">.</span><span class="nf">slice!</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">).</span><span class="nf">class</span> <span class="c1"># => Array</span>
<span class="n">a</span><span class="p">.</span><span class="nf">slice!</span><span class="p">(</span><span class="mi">1</span><span class="o">..</span><span class="mi">0</span><span class="p">).</span><span class="nf">class</span> <span class="c1"># => Array</span>
</code></pre>
<p>Finally, there is currently no constructor nor hook called when making these new copies, so they are never properly constructed.</p>
<p>Imagine this simplified class that relies on <code>@foo</code> holding a hash:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">A</span> <span class="o"><</span> <span class="no">Array</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">)</span>
<span class="k">super</span>
<span class="vi">@foo</span> <span class="o">=</span> <span class="p">{}</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">initialize_copy</span><span class="p">(</span><span class="n">orig</span><span class="p">)</span>
<span class="k">super</span>
<span class="vi">@foo</span> <span class="o">=</span> <span class="vi">@foo</span><span class="p">.</span><span class="nf">dup</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">a</span> <span class="o">=</span> <span class="no">A</span><span class="p">.</span><span class="nf">new</span><span class="p">.</span><span class="nf">flatten</span>
<span class="n">a</span><span class="p">.</span><span class="nf">class</span> <span class="c1"># => A</span>
<span class="n">a</span><span class="p">.</span><span class="nf">instance_variable_get</span><span class="p">(</span><span class="ss">:@foo</span><span class="p">)</span> <span class="c1"># => nil, should never happen</span>
</code></pre>
<p>I feel this violates object orientation.</p>
<p>One solution is to always return the base class (<code>Array</code>/<code>String</code>/...).</p>
<p>Another solution is to return the current subclass. To be object oriented, I feel we must do an actual <code>dup</code> of the object, including copying the instance variables, if any, and calling <code>initialize_copy</code>. Exceptions to this would be (1) explicit documentation, e.g. <code>Array#to_a</code>, or (2) methods inherited from a module (like <code>Enumerable</code> methods for <code>Array</code>).</p>
<p>I'll be glad to fix these once there is a decision made on which way to go.</p> Ruby master - Bug #6085 (Closed): Treatment of Wrong Number of Argumentshttps://bugs.ruby-lang.org/issues/60852012-02-25T15:47:19Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>For brevity, let me abbreviate:</p>
<pre><code>WNA = "wrong number of arguments"
</code></pre>
<p>Ruby could provide more accurate information when raising an ArgumentError for WNA.</p>
<p>Example:</p>
<p>def foo(a, b=42); end<br>
foo # => WNA (0 for 1)<br>
for(1,2,3) # => WNA (3 for 2)</p>
<p>It would be strictly superior if the message said instead "WNA (0 for 1..2)" and "WNA (3 for 1..2)":</p>
<ul>
<li>
<p>more useful as it gives more information at a glance</p>
</li>
<li>
<p>consistent with calling builtin methods:</p>
<p>"".index # => WNA (0 for 1..2)<br>
"".index(1,2,3) # => WNA (3 for 1..2)</p>
</li>
</ul>
<p>Ruby is also not always consistent in its wording when there is a *rest argument:</p>
<p>Enumerator.new # => WNA (0 for 1+)<br>
[].insert # => WNA (at least 1)</p>
<p>File.chown # => WNA (0 for 2+)<br>
Process.kill # => WNA (0 for at least 2)</p>
<p>While reviewing and factorizing all WNA errors, I also found a problematic case:</p>
<p>"".sub(//) # => WNA (1 for 1..2)</p>
<p>It would probably less confusing if it said (1 for 2), as the form without a block requires 2 parameters. Same applies to <code>sub!</code></p>
<p>Also, <code>Module#define_method</code> could say "WNA (3 for 1)" when it actually accepts only up to 2 arguments.</p>
<p>I've implemented two patches that address all these issues.</p>
<p>The first one improves the error message when calling user methods and lambdas.</p>
<p>The second harmonizes the builtin methods and fixes the few that need to be fixed.</p>
<p>The two commits can be found here:</p>
<p><a href="https://github.com/marcandre/ruby/commits/rb_arity_check" class="external">https://github.com/marcandre/ruby/commits/rb_arity_check</a></p>
<p>Complete list of changes:</p>
<ul>
<li>
<p>Improvements:</p>
<p>"".sub(//): WNA (1 for 1..2) => WNA (1 for 2)<br>
(same with sub)<br>
Module#define_method: WNA (3 for 1) => WNA (3 for 1..2)<br>
exec: WNA => WNA (0 for 1+)<br>
Hash.new(1){}: WNA => WNA (1 for 0)<br>
instance_eval("", "", 1, 2)<br>
WNA instance_eval(...) or instance_eval{...}<br>
=> WNA (4 for 1..3)<br>
(same with module_eval and class_eval)<br>
Module#mix: WNA (4 for 1) => WNA (4 for 1..3)<br>
Module#mix, with incorrect arguments: WNA (2 for 1) => wrong arguments</p>
</li>
</ul>
<p>Wording change:</p>
<ul>
<li>
<p>Change of language: WNA (at least 1) => WNA (0 for 1+)<br>
[].insert<br>
extend<br>
"".delete!<br>
"".count</p>
</li>
<li>
<p>Process.kill: WNA (0 for at least 2) => WNA (0 for 2+)</p>
</li>
</ul>
<p>Also, builtin functions calling <code>rb_scan_args</code> with both optional arguments and a rest argument would generate an error of the form "WNA (0 for 2..3+)". After this patch, this would now read "WNA (0 for 2+)", again for consistency. The only two such cases I found are in <code>ext/win32ole.c</code></p>
<p>In addition to giving a more consistent error handling, these commits pave the way to:</p>
<ul>
<li>improved error reporting for parameters with named parameters (forthcoming issue)</li>
<li>improved checking for Proc#curry (see bug <a class="issue tracker-1 status-5 priority-4 priority-default closed" title="Bug: Proc#curry doesn't always detect too many arguments (Closed)" href="https://bugs.ruby-lang.org/issues/5747">#5747</a>)</li>
</ul> Ruby master - Bug #6048 (Closed): {Unbound}Method#hash doesn't always return the right valuehttps://bugs.ruby-lang.org/issues/60482012-02-20T15:19:08Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>{Unbound}Method#hash doesn't always return the right value.</p>
<pre><code>map, collect = Array.instance_method(:map), Array.instance_method(:collect)
map.eql?(collect) # => true
map.hash == collect.hash # => false
</code></pre>
<p>I'm tempted to think that this is an obvious bug with an obvious solution but let me state:</p>
<p>As per the documentation and the design of hash tables, if two objects are <code>eql?</code> then they must have the same hash.</p>
<p>Either <code>map</code> should not be <code>eql?</code> to <code>collect</code> or else their <code>hash</code> should be the same.</p>
<p>As they are identical methods, it is correct that they are <code>eql?</code>, so <code>hash</code> must return the same value.</p>
<p>My proposed behavior passes my strict superiority test and is also "straightforward" as I could find no intent for the current behavior.</p>
<p>One solution is to ensure that all aliased methods are defined using <code>rb_define_alias</code>, which appears to yield the same hash. Another is to compute the <code>hash</code> correctly. Maybe there is a third approach.</p>
<p>I'm not super confident I took the right approach, but here is a patch for the second one. I think it is more robust and more consistent with how <code>{Unbound}Method.eql?</code> is implemented. It may also fix other cases of mismatch between <code>eql?</code> and <code>hash</code>, I didn't investigate further.</p>
<p>I'd be grateful if someone could review the patch (Koichi?) and let me know if I took the right approach and if I put things in the right place.</p>
<a name="Thanks"></a>
<h2 >Thanks<a href="#Thanks" class="wiki-anchor">¶</a></h2>
<p>Marc-André</p> Ruby master - Bug #6029 (Closed): Should OpenStruct implement #eql? and #hash?https://bugs.ruby-lang.org/issues/60292012-02-15T12:33:15Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Currently, OpenStruct have no specialized #eql? and #hash, so:</p>
<pre><code>require 'ostruct'
x = OpenStruct.new(foo: 42)
y = x.dup
x == y # => true
x.eql?(y) # => false
</code></pre>
<p>This means that OpenStruct does not behave like Struct, Array, Hash and other structures by comparing its fields and values.</p>
<p>This also prevents using OpenStructs as hash keys (unless one uses the exact same object as the key), contrary to other structures.</p>
<p>Is there an historical reason for this?</p>
<p>How likely would it be that adding #eql? and #hash create conflict with some fields?</p> Ruby master - Bug #6028 (Closed): OpenStruct.dup doesn't have all its methodshttps://bugs.ruby-lang.org/issues/60282012-02-15T11:44:57Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Dupped OpenStructs don't have the same methods.</p>
<pre><code>x = OpenStuct.new(foo: 42)
x.dup.methods == x.methods # => false
x.respond_to?(:foo) # => true
x.dup.respond_to?(:foo) # => false
</code></pre> Ruby master - Bug #5782 (Closed): File.binwrite doc and hash argumenthttps://bugs.ruby-lang.org/issues/57822011-12-20T16:14:02Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>The doc for <code>File.binwrite</code> doesn't mention the possibility of a fourth argument (option hash), unlike <code>File.write</code>. Judging from the code, this looks like an oversight.</p>
<p>Can we get confirmation that it does accept a fourth parameter and that the doc should be updated?</p>
<p>I would personally simplify the rdoc to state that it <code>File.binwrite</code> does exactly the same as <code>File.write</code> except that it opens the file in binary mode.</p>
<p>Noticed by Konstantin Haase.</p>
<a name="Thanks"></a>
<h2 >Thanks,<a href="#Thanks" class="wiki-anchor">¶</a></h2>
<p>Marc-Andre</p> Ruby master - Bug #5747 (Closed): Proc#curry doesn't always detect too many arguments https://bugs.ruby-lang.org/issues/57472011-12-12T09:30:21Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Currently, Proc#curry checks the validity of the <code>arity</code> argument and will raise an error if:</p>
<ol>
<li>arity is less than the number of required arguments or</li>
<li>arity is more than the maximum number of arguments<br>
Note that simple Procs always accept any number of arguments (even though they may be ignored), so (2) doesn't applies to them, only to lambda's and procs made from methods.</li>
</ol>
<p>#2 isn't done as well as it could in case of limited optional parameters:</p>
<pre><code>def Object.foo(a, b=42); end
def Object.bar(a, b); end
Object.method(:foo).to_proc.curry(3) # => curried proc which will raise an error only when passed it's 3rd parameter
Object.method(:bar).to_proc.curry(3) # => ArgumentError: wrong number of arguments (3 for 2)
Same thing with lambdas
</code></pre>
<p>My proposed fix passes SST:<br>
a) usefulness: "fail-early" principle <a href="https://blade.ruby-lang.org/ruby-core/24130">[ruby-core:24130]</a><br>
b) consistency: both methods can only accept a maximum of 2 parameters and are thus treated consistently when attempting to curry with more than 2 arguments<br>
c) intuitiveness and d) performance: similar</p>
<p>It is straightforward (but not obvious), as it passes NIT (but not ODT).</p> Ruby master - Bug #5746 (Closed): Proc#curry too strict about lambda's arity.https://bugs.ruby-lang.org/issues/57462011-12-12T02:08:08Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Currently, Proc#curry raises an error when you attempt to curry a lambda with optional (but limited) arguments:</p>
<pre><code>l = ->(arg = 42) {}
l.curry(1) # => ArgumentError: wrong number of arguments (1 for 0)
</code></pre>
<p>Note that Proc#curry behaves correctly if the Proc was created from a method, even though arguments are treated the same way:</p>
<pre><code>def Object.foo(arg = 42); end
m = Object.method(:foo).to_proc
m.class # => Proc, same as 'l'
m.lambda? # => true, same as 'l'
m.curry(1) # => curried proc
</code></pre>
<p>Referring to my evaluation method, my proposed fix passes SST:<br>
a) usefulness: way more useful, as it makes it possible to do something that is not currently possible<br>
b) consistency: makes it consistent with equivalent method<br>
c) intuitiveness and d) performance: similar</p>
<p>It is straightforward (but not obvious), as it passes NIT (but not ODT).</p>
<p>This bug is a consequence of the redmine issue 5694; this will be fixed automatically when 5694 is fixed.</p> Ruby master - Bug #5694 (Closed): Proc#arity doesn't take optional arguments into account. https://bugs.ruby-lang.org/issues/56942011-12-01T20:16:05Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Currently:</p>
<pre><code>->(foo = 42){}.arity # => 0, should be -1
</code></pre>
<p>This is contrary to the documentation and to what we should expect from the equivalent method definition.</p>
<p>Fixed in trunk, requesting backport for the 1.9 line.</p> Ruby master - Bug #5307 (Closed): Matrix & subclasseshttps://bugs.ruby-lang.org/issues/53072011-09-11T05:22:18Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Matrix doesn't deal properly with subclasses:</p>
<pre><code>Class.new(Matrix)[[42]].class # => Matrix
</code></pre> Ruby master - Bug #5273 (Closed): Float#round returns the wrong floats for higher precisionhttps://bugs.ruby-lang.org/issues/52732011-09-05T05:43:55Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Float#round returns the wrong floats for higher precision.</p>
<p>Rounding can be off:<br>
2.5e-22.round(22) # => 2.0e-22</p>
<p>It can also return values that have extra decimals:<br>
2.5e-31.round(31) # => 3.0000000000000003e-31<br>
2.5e-36.round(36) # => 2.9999999999999998e-36</p>
<p>Both errors can occur at the same time too:<br>
2.5e-39.round(39) # => 2.0000000000000002e-39</p>
<p>I believe these errors occur only for ndigits >= 22. For ndigits > 22, 10**(-ndigits) is not an exact Float (as 5 ** 23 won't fit in the 53 bits of a double's mantissa). For ndigits < 22, there should be enough bits left to avoid rounding errors.</p>
<p>For ndigits >= 22, the algorithm to use should be similar to the one used to convert doubles to string.</p>
<p>Hopefully, this is the last bug for #round with a given precision.</p> Ruby master - Bug #5228 (Closed): Integer#round fails on some big negative numbershttps://bugs.ruby-lang.org/issues/52282011-08-25T07:50:29Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Integer#round fails for some big negative numbers:</p>
<p>(+25 * 10<strong>70).round(-71) # => 30...00<br>
(-25 * 10</strong>70).round(-71) # => -20...00, should be -30...00</p> Ruby master - Bug #5227 (Closed): Float#round fails on corner caseshttps://bugs.ruby-lang.org/issues/52272011-08-25T06:03:50Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Float#round fails on some corner cases:</p>
<p>42.0.round(300) # => 42.0<br>
42.0.round(308) # => Infinity, should be 42.0<br>
42.0.round(309) # => 42.0</p>
<p>1.0e307.round(1) # => 1.0e307<br>
1.0e307.round(2) # => Infinity, should be 1.0e307</p>
<p>These occur when the exponent of the intermediate value overflows.</p>
<p>The original code already had criteria for extreme values, but we can find much tighter ones, as explained in the patch below. This fixes the bugs above and optimizes for most trivial cases.</p>
<p>I'd be grateful if someone could look it over before I commit it, thanks.</p>
<p>diff --git a/numeric.c b/numeric.c<br>
index 272bbd1..22608c9 100644<br>
--- a/numeric.c<br>
+++ b/numeric.c<br>
@@ -1491,18 +1491,37 @@ flo_round(int argc, VALUE *argv, VALUE num)<br>
VALUE nd;<br>
double number, f;<br>
int ndigits = 0;</p>
<ul>
<li>
<p>int binexp;<br>
long val;</p>
<p>if (argc > 0 && rb_scan_args(argc, argv, "01", &nd) == 1) {<br>
ndigits = NUM2INT(nd);<br>
}<br>
number = RFLOAT_VALUE(num);</p>
</li>
</ul>
<ul>
<li>f = pow(10, abs(ndigits));</li>
<li>
<li>if (isinf(f)) {</li>
<li>
<pre><code> if (ndigits < 0) number = 0;
</code></pre>
</li>
<li>}</li>
<li>else {</li>
</ul>
<ul>
<li>frexp (number , &binexp);</li>
<li>
</ul>
<p>+/* Let <code>exp</code> be such that <code>number</code> is written as: "0.#{digits}e#{exp}",</p>
<ul>
<li>i.e. such that 10 ** (exp - 1) <= |number| < 10 ** exp</li>
<li>Recall that up to 17 digits can be needed to represent a double,</li>
<li>so if ndigits + exp >= 17, the intermediate value (number * 10 ** ndigits)</li>
<li>will be an integer and thus the result is the original number.</li>
<li>If ndigits + exp <= 0, the result is 0 or "1e#{exp}", so</li>
<li>if ndigits + exp < 0, the result is 0.</li>
<li>We have:</li>
<li>
<pre><code> 2 ** (binexp-1) <= |number| < 2 ** binexp
</code></pre>
</li>
<li>
<pre><code> 10 ** ((binexp-1)/log_2(10)) <= |number| < 10 ** (binexp/log_2(10))
</code></pre>
</li>
<li>
<pre><code> If binexp >= 0, and since log_2(10) = 3.322259:
</code></pre>
</li>
<li>
<pre><code> 10 ** (binexp/4 - 1) < |number| < 10 ** (binexp/3)
</code></pre>
</li>
<li>
<pre><code> binexp/4 <= exp <= binexp/3
</code></pre>
</li>
<li>
<pre><code> If binexp <= 0, swap the /4 and the /3
</code></pre>
</li>
<li>
<pre><code> So if ndigits + binexp/(3 or 4) >= 17, the result is number
</code></pre>
</li>
<li>
<pre><code> If ndigits + binexp/(4 or 3) < 0 the result is 0
</code></pre>
</li>
</ul>
<p>+*/</p>
<ul>
<li>if ((long)ndigits * (4 - (binexp < 0)) + binexp < 0) {</li>
<li>
<pre><code> number = 0;
</code></pre>
</li>
<li>}</li>
<li>else if ((long)(ndigits - 17) * (3 + (binexp < 0)) + binexp < 0) {</li>
<li>
<pre><code> f = pow(10, abs(ndigits));
if (ndigits < 0) {
double absnum = fabs(number);
if (absnum < f) return INT2FIX(0);
</code></pre>
</li>
</ul> Ruby master - Bug #5179 (Closed): Complex#rationalize and to_r with approximate zeroshttps://bugs.ruby-lang.org/issues/51792011-08-10T10:41:15Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Currently, Complex#rationalize and Complex#to_r raise a RangeError if the imaginary part is nonzero <em>or is a Float</em>. Note that a BigDecimal(0) is accepted, though:</p>
<pre><code>Complex(1, 0).to_r # => Rational(1,1)
Complex(1, BigDecimal("0.0")).to_r # => Rational(1,1)
Complex(1, 0.0).to_r # => RangeError
</code></pre>
<p>This is inconsistent. I recommend not raising an error for 0.0 (Float or BigDecimal). Any objection?</p> Ruby master - Bug #5178 (Closed): Complex#rationalize should rationalizehttps://bugs.ruby-lang.org/issues/51782011-08-10T10:39:36Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Complex#rationalize currently calls <code>to_r</code> on the real part instead of <code>rationalize</code>:</p>
<p>f = 1/3.0<br>
c = Complex(f)<br>
c.to_r == f.to_r # => true<br>
c.rationalize == f.rationalize # => false</p>
<p>Should I not commit this to 1.9.3 too?</p>
<p>diff --git a/complex.c b/complex.c<br>
index 78f0902..1b76074 100644<br>
--- a/complex.c<br>
+++ b/complex.c<br>
@@ -1335,7 +1335,8 @@ nucomp_to_f(VALUE self)</p>
<ul>
<li>call-seq:</li>
<li>cmp.to_r -> rational</li>
<li>
</ul>
<ul>
<li>
<ul>
<li>Returns the value as a rational if possible.</li>
</ul>
</li>
</ul>
<ul>
<li>
<ul>
<li>If the imaginary part is exactly 0, returns the real part as a Rational,</li>
</ul>
</li>
<li>
<ul>
<li>otherwise a RangeError is raised.<br>
*/<br>
static VALUE<br>
nucomp_to_r(VALUE self)<br>
@@ -1354,14 +1355,22 @@ nucomp_to_r(VALUE self)</li>
<li>call-seq:</li>
<li>cmp.rationalize([eps]) -> rational</li>
<li>
</ul>
</li>
</ul>
<ul>
<li>
<ul>
<li>Returns the value as a rational if possible. An optional argument</li>
</ul>
</li>
<li>
<ul>
<li>eps is always ignored.</li>
</ul>
</li>
</ul>
<ul>
<li>
<ul>
<li>If the imaginary part is exactly 0, returns the real part as a Rational,</li>
</ul>
</li>
<li>
<ul>
<li>otherwise a RangeError is raised.<br>
*/<br>
static VALUE<br>
nucomp_rationalize(int argc, VALUE *argv, VALUE self)<br>
{</li>
</ul>
</li>
<li>get_dat1(self);</li>
<li>rb_scan_args(argc, argv, "01", NULL);</li>
</ul>
<ul>
<li>return nucomp_to_r(self);</li>
</ul>
<ul>
<li>
<li>if (k_inexact_p(dat->imag) || f_nonzero_p(dat->imag)) {</li>
<li>
<pre><code> VALUE s = f_to_s(self);
</code></pre>
</li>
<li>
<pre><code> rb_raise(rb_eRangeError, "can't convert %s into Rational",
</code></pre>
</li>
<li>
<pre><code> StringValuePtr(s));
</code></pre>
</li>
<li>}</li>
<li>return rb_funcall(dat->real, rb_intern("rationalize"), argc, argv);<br>
}</li>
</ul> Ruby master - Bug #5070 (Closed): CSV.generate should not modify the given option hashhttps://bugs.ruby-lang.org/issues/50702011-07-22T04:23:02Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Currently:</p>
<pre><code>CSV.generate( {}.freeze ) # => RuntimeError: can't modify frozen Hash
</code></pre>
<p>I'm not sure where these tests would ideally go; In the attached patch, I've put them at the end of csv/test_interface</p>
<p>If you can, please make the modifications you see fit, or else I'll commit this in a of week or two.</p>
<p>(From <a href="http://stackoverflow.com/questions/6759487/ruby-hash-object-changed-by-csv-library" class="external">http://stackoverflow.com/questions/6759487/ruby-hash-object-changed-by-csv-library</a> )</p> Ruby master - Bug #3434 (Closed): Specs for coercion?https://bugs.ruby-lang.org/issues/34342010-06-13T15:29:24Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
What are the official specs of coercion for mathematical classes?</p>
<p>I will take Matrix as an example, but my questions are meant to be for the general case.</p>
<p>My understanding is that for a <code>obj.coerce(obj_2)</code> should return <code>[compatible_2, compatible]</code> such that <code>compatible2.send(some_operation, compatible)</code> returns (if possible) a meaningful result.</p>
<p>Can we assume anything more about coercion? I'm asking because I find in test_matrix (@m1 being a Matrix):</p>
<p>def test_scalar_mul<br>
s1 = @m1.coerce(1).first<br>
assert_equal(Matrix[[1]], (s1 * 1) * Matrix[[1]])<br>
assert_equal(Vector[2], s1 * Vector[2])<br>
assert_equal(Matrix[[2]], s1 * Matrix[[2]])<br>
o = Object.new<br>
def o.coerce(x)<br>
[1, 1]<br>
end<br>
assert_equal(1, s1 * o)<br>
end</p>
<ol>
<li>Should the first and last assert work? Are implementers of other mathematical classes mandated/encouraged to provide that level of compatibility? Are users of <code>coerce</code> encouraged (or guaranteed success) when doing any other operation than <code>compatible2 * compatible</code> or similar?</li>
</ol>
<p>My feeling is that the only thing one should do with the results of coerce is to call an operation on the first element and pass the second element. Doing operations using only one of the two returned elements with another new object should yield undetermined results.</p>
<p>If this is the case, I feel the Matrix library would be best to assume that Scalar#* is called with a Matrix or Vector (remember that the Scalar is not meant to be used directly by anybody else than the Matrix lib), and these two assert would <em>not</em> work.</p>
<ol start="2">
<li>
<p>The second assert is clearly implementation dependant. In the current implementation, both Vector and Matrix use Matrix::Scalar as a temporary class, but that could change.</p>
</li>
<li>
<p>I am assuming that compatible doesn't have to be equal?, eql? or == to obj nor of the same class, and the same is true for compatible_2 vs obj_2, right? Thus the third assert isn't a spec guaranteed for all implementations.</p>
</li>
<li>
<p>Finally, a somewhat trivial question: should <code>obj.coerce(obj_2)</code> succeed if <code>obj</code> and <code>obj_2</code> are of the same class (and presumably return <code>[obj_2, obj]</code>)? Clearly this is not very useful, but the specs should be made precise.</p>
</li>
</ol>
<p>This is the case for Numeric and is explicit in the documentation but fails for Matrix:</p>
<pre><code> Matrix.I(2).coerce(Matrix.I(2)) # => TypeError: Matrix can't be coerced into Matrix
</code></pre>
<p>Coercion should always work for the trivial case of two objects of the same class, right?</p>
<a name="Thanks"></a>
<h2 >Thanks.<a href="#Thanks" class="wiki-anchor">¶</a></h2>
<p>Marc-André<br>
=end</p> Ruby master - Bug #3350 (Closed): Protected methods & documentationhttps://bugs.ruby-lang.org/issues/33502010-05-27T15:28:46Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
The official doc currently states that Object#methods "returns a list of the names of methods publicly accessible".</p>
<p>Similarly, Module#instance_methods states that it returns "the public methods" of the Module. Note that the doc was modified in r19900, but I feel the wording "instance method that is callable from outside" still implies public only.</p>
<p>The current behavior doesn't fit the doc, since protected methods are also matched:</p>
<pre><code> class X
def protected_method; end
protected :protected_method
end
X.new.methods.include?(:protected_method) #=> true
X.instance_methods.include?(:protected_method) #=> true
</code></pre>
<p>The documentation for Module#method_defined? on the other states it matches public and protected methods.</p>
<p>Should I change the doc to reflect the current behavior, as per the patch below?</p>
<p>I'm asking in part because I lack experience with protected methods and I am surprised by the fact that protected methods are matched by these "default" methods.</p>
<p>The fact that Object#respond_to? also matches protected is even less practical since there is no "public-only" equivalent. I might be mistaken, but I believe that the only way of knowing if obj responds publicly to :foo is to do something like</p>
<pre><code> publicly_responds = obj.public_method(:foo) rescue false
</code></pre>
<p>I dislike the fact that obj.respond_to?(:foo) && obj.foo might raise a NoMethodError.</p>
<p>It looks like this was discussed a in [ruby_dev:40461], but I don't know the outcome.</p>
<p>I'm curious: what examples exist where one would want to match public and protected methods but not private ones?</p>
<p>Matz, is there any chance the handling of #respond_to?, #methods, etc..., with regards to protected methods will change (in 1.9.2 or later)?</p>
<p>--<br>
Marc-André</p>
<p>diff --git a/class.c b/class.c<br>
index c586f7a..683fa7b 100644<br>
--- a/class.c<br>
+++ b/class.c<br>
@@ -865,8 +865,8 @@ class_instance_method_list(int argc, VALUE *argv, VALUE mod, int (*func) (ID, lo</p>
<ul>
<li>call-seq:</li>
<li>
<pre><code>mod.instance_methods(include_super=true) -> array
</code></pre>
</li>
<li>
</ul>
<ul>
<li>
<ul>
<li>Returns an array containing the names of instance methods that is callable</li>
</ul>
</li>
<li>
<ul>
<li>from outside in the receiver. For a module, these are the public methods;</li>
</ul>
</li>
</ul>
<ul>
<li>
<ul>
<li>Returns an array containing the names of the public and protected instance</li>
</ul>
</li>
<li>
<ul>
<li>methods in the receiver. For a module, these are the public and protected methods;</li>
<li>for a class, they are the instance (not singleton) methods. With no</li>
<li>argument, or with an argument that is <code>false</code>, the</li>
<li>instance methods in <i>mod</i> are returned, otherwise the methods<br>
@@ -954,6 +954,7 @@ rb_class_public_instance_methods(int argc, VALUE *argv, VALUE mod)</li>
<li>Returns an array of the names of singleton methods for <i>obj</i>.</li>
<li>If the optional <i>all</i> parameter is true, the list will include</li>
<li>methods in modules included in <i>obj</i>.</li>
</ul>
</li>
<li>
<ul>
<li>Only public and protected singleton methods are returned.</li>
<li>
<li>
<pre><code>module Other
</code></pre>
</li>
<li>
<pre><code> def three() end
</code></pre>
</li>
</ul>
</li>
</ul>
<p>diff --git a/object.c b/object.c<br>
index a7f05a1..351d16f 100644<br>
--- a/object.c<br>
+++ b/object.c<br>
@@ -1755,7 +1755,7 @@ rb_mod_const_defined(int argc, VALUE *argv, VALUE mod)</p>
<ul>
<li>call-seq:</li>
<li>
<pre><code>obj.methods -> array
</code></pre>
</li>
<li>
</ul>
<ul>
<li>
<ul>
<li>Returns a list of the names of methods publicly accessible in</li>
</ul>
</li>
</ul>
<ul>
<li>
<ul>
<li>Returns a list of the names of public and protected methods of</li>
<li>
<i>obj</i>. This will include all the methods accessible in</li>
<li>
<i>obj</i>'s ancestors.</li>
<li>
</ul>
</li>
</ul>
<p>=end</p> Ruby master - Bug #3225 (Closed): lib/uri/mailto.rb slightly wrong regexphttps://bugs.ruby-lang.org/issues/32252010-04-30T13:24:56Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Looking for example of the 3rd parameter of value 'N' for Regexp.new, I noticed in lib/uri/mailto.rb</p>
<p>HEADER_REGEXP = Regexp.new(HEADER_PATTERN, 'N').freeze</p>
<p>Unless I'm mistaken, the 'N' in second position is simply a flag for case insensitivity, but HEADER_PATTERN already is, so it should either be</p>
<p>HEADER_REGEXP = Regexp.new(HEADER_PATTERN).freeze</p>
<p>or</p>
<p>HEADER_REGEXP = Regexp.new(HEADER_PATTERN, nil, 'N').freeze</p>
<p>but I don't know which one...<br>
=end</p> Ruby master - Bug #3224 (Closed): Regexp.new("...", nil, "n") is not documentedhttps://bugs.ruby-lang.org/issues/32242010-04-30T13:15:06Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
While fixing the error messages for the number of parameters ( r27558 ), I noticed that Regexp.new accepts a third undocumented parameter.</p>
<p>Is it supported? If so it should be documented.</p>
<p>I also note that test_regexp.rb tests for the third parameter being "u", even though this has no effect. Maybe these tests should be removed?<br>
=end</p> Ruby master - Bug #3192 (Closed): Missing Set#keep_if, select! [patch]https://bugs.ruby-lang.org/issues/31922010-04-23T14:40:16Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Set (& SortedSet) were forgotten when adding keep_if and select!</p>
<p>Unless there is objection, I'll commit the attached patch (and add tests to RubySpec).<br>
=end</p> Ruby master - Bug #3169 (Closed): RDoc crossref confused by instance and class methods having sam...https://bugs.ruby-lang.org/issues/31692010-04-19T09:39:40Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
The documentation for the two methods below will both have a reference to X.foo (which appeared first). The "See X#foo" should reference to the instance method instead.</p>
<p>class X<br>
# The class method. See X#foo<br>
def self.foo<br>
end</p>
<pre><code> # The instance method. See X.foo
def foo
end
</code></pre>
<p>end<br>
=end</p> Ruby master - Bug #3128 (Closed): Randomness specshttps://bugs.ruby-lang.org/issues/31282010-04-11T15:34:01Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
What should be the Ruby specs for the new Random class (and existing Kernel.{s}rand)?</p>
<p>More precisely: what should one expect of any Ruby implementation?</p>
<p>Several degrees of similarity with MRI are possible:</p>
<p>Say r = Random.new(42) and N is an Integer</p>
<ol start="0">
<li>r.rand(N) is included in 0...N</li>
<li>r.rand(N) will eventually return all values in 0...N</li>
<li>r.rand(N) will return any particular value in 0...N with a probability of around 1/N<br>
<insert any any of the known random tests and/or a minimal period></li>
<li>r is a Mersenne Twister</li>
<li>r is MT19937</li>
<li>r.rand(N) generates the same particular string on all platforms</li>
</ol>
<p>Implementers are ultimately free to choose whichever implementation they prefer, of course.</p>
<p>Still, it would be preferable to state what is the expect behavior for the Ruby language, not just for MRI. If MRI's guarantees are stronger, these should be stated as such.</p>
<p>Current state of affairs:</p>
<p>The documentation for Random class states that it is a Mersenne Twister pseudo number generator (but doesn't state which), so this corresponds to level (3) above.</p>
<p>Kernel.rand states that <em>currently</em>, r is a modified MT19937.</p>
<p>The Ruby Standardization WG Draft doesn't document Kernel.rand yet (nor Random, of course).</p>
<p>Rubinius' implementation currently guarantees level 0 (and also level 1 if N is not too big)</p>
<p>JRuby's implementation guarantees level 1 (and also level 2 if N is not too big)</p>
<p>Python and Java both guarantee the same particular sequence; other algorithms might be available as subclasses of their Random class.</p>
<hr>
<p>My personal choice would be in line with Java and Python: insure the exact same sequence for the Random class. Implementations are free to provide subclasses of Random for different/better/faster algorithms.</p>
<p>If deemed preferable, Kernel.rand could have much lower required standards to allow for better speed, in which case level (2) above seems like the strict minimum.<br>
=end</p> Ruby master - Bug #3104 (Closed): Random: seeding issueshttps://bugs.ruby-lang.org/issues/31042010-04-07T15:08:35Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
I think there are a couple of very small errors with the seeding of the Random class.</p>
<ol>
<li>
<p>Seeding sometimes ignores the high bit of seed data.</p>
<p>Random.new((1<<64)-1).rand == Random.new((1 << 65) -1).rand</p>
<a name="gt-true-should-be-false"></a>
<h1 >=> true, should be false<a href="#gt-true-should-be-false" class="wiki-anchor">¶</a></h1>
</li>
</ol>
<p>Probably some leftover code?</p>
<p>diff --git a/random.c b/random.c<br>
index 02d081c..447e59f 100644<br>
--- a/random.c<br>
+++ b/random.c<br>
@@ -411,8 +411,6 @@ rand_init(struct MT *mt, VALUE vseed)<br>
init_genrand(mt, buf[0]);<br>
}<br>
else {</p>
<ul>
<li>
<pre><code> if (buf[len-1] == 1) /* remove leading-zero-guard */
</code></pre>
</li>
<li>
<pre><code> len--;
init_by_array(mt, buf, len);
</code></pre>
}<br>
if (buf != buf0) xfree(buf);</li>
</ul>
<ol start="2">
<li>
<p>Treatment of negative seed values is currently platform dependent for all negative fixnums. From the same negative seed, the random sequence can be different on 32 bit platforms than on 64 bit ones.</p>
<p>Random.new(-1).rand == Random.new((1<<63) -1).rand</p>
<a name="gt-true-on-64-bit-platform-false-on-32-bit"></a>
<h1 >=> true on 64 bit platform, false on 32 bit<a href="#gt-true-on-64-bit-platform-false-on-32-bit" class="wiki-anchor">¶</a></h1>
<p>Random.new(-1).rand == Random.new((1<<31) -1).rand</p>
<a name="gt-false-on-64-bit-platform-true-on-32-bit"></a>
<h1 >=> false on 64 bit platform, true on 32 bit<a href="#gt-false-on-64-bit-platform-true-on-32-bit" class="wiki-anchor">¶</a></h1>
</li>
</ol>
<p>The simple solution below ignores the sign (which is what's done in case of negative Bignum). This means that the same values will result from seeding with x or -x. Another solution would be to use the lowest bit for the sign (for both fixnums and bignums) so as to avoid this collision, or raise an error in case of negative seeds.</p>
<p>diff --git a/random.c b/random.c<br>
index 02d081c..272f7b5 100644<br>
--- a/random.c<br>
+++ b/random.c<br>
@@ -367,6 +367,7 @@ rand_init(struct MT *mt, VALUE vseed)<br>
{<br>
volatile VALUE seed;<br>
long blen = 0;</p>
<ul>
<li>long fixnum_seed;<br>
int i, j, len;<br>
unsigned int buf0[SIZEOF_LONG / SIZEOF_INT32 * 4], *buf = buf0;</li>
</ul>
<p>@@ -374,9 +375,11 @@ rand_init(struct MT *mt, VALUE vseed)<br>
switch (TYPE(seed)) {<br>
case T_FIXNUM:<br>
len = 1;</p>
<ul>
<li>
<pre><code> buf[0] = (unsigned int)(FIX2ULONG(seed) & 0xffffffff);
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> fixnum_seed = FIX2LONG(seed);
</code></pre>
</li>
<li>
<pre><code> if (fixnum_seed < 0) fixnum_seed = -fixnum_seed;
</code></pre>
</li>
<li>
<pre><code> buf[0] = (unsigned int)(fixnum_seed & 0xffffffff);
</code></pre>
</li>
</ul>
<p>#if SIZEOF_LONG > SIZEOF_INT32</p>
<ul>
<li>
<pre><code> if ((buf[1] = (unsigned int)(FIX2ULONG(seed) >> 32)) != 0) ++len;
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> if ((buf[1] = (unsigned int)(fixnum_seed >> 32)) != 0) ++len;
</code></pre>
</li>
</ul>
<p>#endif<br>
break;<br>
case T_BIGNUM:</p>
<ol start="3">
<li>Finally, I was wondering if there wasn't a typo trashing some of the bits in the initial states when seeding with an array:</li>
</ol>
<p>diff --git a/random.c b/random.c<br>
index 02d081c..f3db095 100644<br>
--- a/random.c<br>
+++ b/random.c<br>
@@ -151,7 +151,7 @@ init_by_array(struct MT *mt, unsigned int init_key[], int key_length)<br>
if (i>=N) { mt->state[0] = mt->state[N-1]; i=1; }<br>
}</p>
<ul>
<li>mt->state[0] = 0x80000000U; /* MSB is 1; assuring non-zero initial array */</li>
</ul>
<ul>
<li>mt->state[0] |= 0x80000000U; /* MSB is 1; assuring non-zero initial array */<br>
}</li>
</ul>
<p>static void</p>
<p>These changes will surely create test failures which should be trivial to fix.<br>
=end</p> Ruby master - Bug #3089 (Closed): limited size for Array#combination [patch]https://bugs.ruby-lang.org/issues/30892010-04-04T05:54:56Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
I would expect the following to work, but it raises an error</p>
<p>(0..100).to_a.combination(50).first(42)<br>
# => RangeError: too big for combination</p>
<p>There is a limit of 1 << 31 potential results (or 1 <<63, depending on the platform).</p>
<p>Since there is an explicit test for this, I learned the hard way I better ask if there is a valid reason for this artificial limit for #combination ?</p>
<p>If not, and unless there is objection, I'll commit the attached patch.</p>
<p>Note: I noticed this when implementing the block form of #product where a similar limit exists. Since #product without a block needs to return an array of this size, it is sensible that an error is raised in that case.<br>
When an block is given, though, I didn't see why there should be a limit, so the limitation applies only to the form without a block. This does mean, though, that arr.product(...) might not behave the same as arr.to_enum(:product, ...).to_a, at least until Enumerators have a length method (see issue <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: the length for an enumerator generated by Array#permutation and Array#combination (Closed)" href="https://bugs.ruby-lang.org/issues/2673">#2673</a>)<br>
=end</p> Ruby master - Bug #3081 (Closed): lib/http wrong behavior for chunked readinghttps://bugs.ruby-lang.org/issues/30812010-04-03T02:25:06Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Take the following code:</p>
<p>require 'net/http'<br>
uri = URI.parse("<a href="http://banners.wunderground.com/banner/krd_condV2/language/www/US/FL/Miami.gif" class="external">http://banners.wunderground.com/banner/krd_condV2/language/www/US/FL/Miami.gif</a>")<br>
http = Net::HTTP.new(uri.host, uri.port)</p>
<p>http.request_get(uri.request_uri) do |res|<br>
res.read_body do |chunk|<br>
puts "read #{chunk.size} bytes"<br>
break<br>
end<br>
puts "Done"<br>
end<br>
puts "Bye"</p>
<p>in Ruby 1.8.7 or in 1.9.2dev, it outputs the following:</p>
<p>read 1024 bytes<br>
Done<br>
/usr/local/rubydev/lib/ruby/1.9.1/net/http.rb:2433:in <code>read_chunked': wrong chunk size line: (Net::HTTPBadResponse) from /usr/local/rubydev/lib/ruby/1.9.1/net/http.rb:2411:in </code>read_body_0'<br>
from /usr/local/rubydev/lib/ruby/1.9.1/net/http.rb:2371:in <code>read_body' from /usr/local/rubydev/lib/ruby/1.9.1/net/http.rb:2396:in </code>body'<br>
from /usr/local/rubydev/lib/ruby/1.9.1/net/http.rb:2335:in <code>reading_body' from /usr/local/rubydev/lib/ruby/1.9.1/net/http.rb:1185:in </code>transport_request'<br>
from /usr/local/rubydev/lib/ruby/1.9.1/net/http.rb:1169:in <code>request' from /usr/local/rubydev/lib/ruby/1.9.1/net/http.rb:1162:in </code>block in request'<br>
from /usr/local/rubydev/lib/ruby/1.9.1/net/http.rb:627:in <code>start' from /usr/local/rubydev/lib/ruby/1.9.1/net/http.rb:1160:in </code>request'<br>
from /usr/local/rubydev/lib/ruby/1.9.1/net/http.rb:1073:in <code>request_get' from b.rb:5:in </code>'</p>
<p>There's apparently nothing wrong with the server; remove the 'break' statement and you get instead:</p>
<p>read 1024 bytes<br>
read 597 bytes<br>
read 2 bytes<br>
Done<br>
Bye<br>
=end</p> Ruby master - Bug #3027 (Closed): Random#rand(nil)https://bugs.ruby-lang.org/issues/30272010-03-28T09:06:42Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Hi Nobu.</p>
<p>Looking at Random#rand, I notice that passing nil has the same result as not passing any argument.</p>
<p>Either it should raise an ArgumentError like the documentation implies, or else the documentation should be modified.</p>
<p>I would argue to raise an error because:</p>
<ul>
<li>it is easy to pass nothing, or pass 1.0 instead, and get the same result if that is what is desired</li>
<li>it could hide an error in the code, where the result is unexpectedly nil but the programmer didn't think about it (like whiny nils in rails)<br>
=end</li>
</ul> Ruby master - Bug #3022 (Closed): What are $. and ARGF.lineno ?https://bugs.ruby-lang.org/issues/30222010-03-27T04:13:59Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin</p>
<ol>
<li>$. is not officially documented.</li>
</ol>
<p>This makes it difficult to know if it works as expected or not...</p>
<p>The Ruby Prog Language (Flanagan & Matz) states:<br>
"The number of the last line read from the current input file. Equivalent to ARGF.lineno."</p>
<p>This is not true in trunk, as demonstrated by:</p>
<p>$ rubydev -e "<br>
ARGF.gets<br>
File.open('/etc/passwd'){|f| f.gets; f.gets}<br>
p $., ARGF.lineno<br>
" /etc/hosts<br>
2<br>
1</p>
<p>What is the "current input file"? Not clear, but it's not thread local, as shown:</p>
<p>$ rubydev -e "<br>
p $.<br>
Thread.new{File.open('/etc/passwd').gets; p $. }.join;<br>
p $.<br>
"<br>
0<br>
1<br>
1</p>
<ol start="2">
<li>ARGF.lineno does not conform to its doc.</li>
</ol>
<p>The doc states:</p>
<p>Returns the current line number of the current file in ARGF. This value<br>
can be set manually with ARGF.lineno=.</p>
<p>Reading this, I would expect ARGF.lineno to be the same as ARGF.to_io.lineno.</p>
<p>That is not the case:</p>
<p>rubydev -e 'p "#{ARGF.lineno} #{ARGF.to_io.lineno}" while ARGF.gets' /etc/hosts /etc/passwd<br>
"1 1"<br>
"2 2"<br>
...<br>
"25 1"<br>
"26 2"<br>
...</p>
<ol>
<li>
<p>Maybe the best definition would be that $. returns the number of line read operations issued, from the last time an IO was read in the current thread?</p>
</li>
<li>
<p>I suggest the documentation of ARGF.lineno be changed to:</p>
</li>
</ol>
<p>Returns the current line number of ARGF as a whole. This value<br>
can be set manually with ARGF.lineno=.</p>
<p>See also <a href="https://blade.ruby-lang.org/ruby-core/26303">[ruby-core:26303]</a><br>
=end</p> Ruby 1.8 - Bug #3011 (Closed): caller for recursive functionhttps://bugs.ruby-lang.org/issues/30112010-03-25T10:38:53Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
For some reason, Ruby 1.8 will skip multiple copies of the same method. In case of a recursive function call, the behavior is different from Ruby 1.9 and seems wrong.</p>
<p>Here's the rubyspec I just committed:</p>
<pre><code> it "returns one entry per call, even for recursive methods" do
def recurse(n)
return caller if n <= 0
recurse(n-1)
end
(recurse(3).size - recurse(2).size).should == 1
end
</code></pre>
<p>The following patch doesn't seem to yield any new failure with make test, make test-all, nor the caller specs:</p>
<p>diff --git a/eval.c b/eval.c<br>
index 3407548..65fb970 100644<br>
--- a/eval.c<br>
+++ b/eval.c<br>
@@ -6468,9 +6468,6 @@ backtrace(lev)<br>
}<br>
for (; frame && (n = frame->node); frame = frame->prev) {<br>
if (frame->prev && frame->prev->last_func) {</p>
<ul>
<li>
<pre><code> if (frame->prev->node == n) {
</code></pre>
</li>
<li>
<pre><code> if (frame->prev->last_func == frame->last_func) continue;
</code></pre>
</li>
<li>
<pre><code> }
snprintf(buf, BUFSIZ, "%s:%d:in `%s'",
n->nd_file, nd_line(n),
rb_id2name(frame->prev->last_func));
</code></pre>
</li>
</ul>
<p>Nobu, can you recall what was the reason for these lines ( r10593 ) ?<br>
=end</p> Ruby master - Bug #2830 (Closed): Some methods raise ArgumentError instead of TypeErrorhttps://bugs.ruby-lang.org/issues/28302010-03-02T13:45:08Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Some methods of Ruby 1.9 expect integers/reals and call internally nurat_int_value/nurat_int_check. These functions raise an ArgumentError when the argument is not an Integer, instead of a TypeError.</p>
<p>Thus:<br>
42.gcd(:foo) # => ArgumentError, should be TypeError<br>
42.lcm(:foo) # => ditto<br>
42.gcdlcm(:foo) # => ditto<br>
Rational(:foo,1) # => ditto</p>
<p>Note that on the other hand:<br>
Rational(nil, 1) # => TypeError<br>
Rational(:foo) # => TypeError</p>
<p>In a similar fashion:<br>
Complex.rect(nil) # => ArgumentError, should be TypeError<br>
Complex.polar(nil) # => ditto</p>
<p>Unless there is objection, I will commit the following patch (and fix RubySpec):</p>
<p>diff --git a/complex.c b/complex.c<br>
index 214d3a2..6742257 100644<br>
--- a/complex.c<br>
+++ b/complex.c<br>
@@ -377,7 +377,7 @@ nucomp_real_check(VALUE num)<br>
break;<br>
default:<br>
if (!k_numeric_p(num) || !f_real_p(num))</p>
<ul>
<li>
<pre><code> rb_raise(rb_eArgError, "not a real");
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> rb_raise(rb_eTypeError, "not a real");
</code></pre>
}<br>
}</li>
</ul>
<p>diff --git a/rational.c b/rational.c<br>
index 65d3cf4..f5a6d26 100644<br>
--- a/rational.c<br>
+++ b/rational.c<br>
@@ -419,7 +419,7 @@ nurat_int_check(VALUE num)<br>
break;<br>
default:<br>
if (!k_numeric_p(num) || !f_integer_p(num))</p>
<ul>
<li>
<pre><code> rb_raise(rb_eArgError, "not an integer");
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> rb_raise(rb_eTypeError, "not an integer");
</code></pre>
}<br>
}<br>
=end</li>
</ul> Ruby master - Bug #2829 (Closed): Missing documentation for Exception subclasses.https://bugs.ruby-lang.org/issues/28292010-03-02T13:38:53Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
I noticed that the documentation for Exception subclasses are either that of Exception itself, or just plain non-sensical because they are actually missing (see ZeroDivisionError, FiberError, ...)</p>
<p>It would be preferable if the Exception classes were at least briefly described.</p>
<p>I've made a first draft of a description for all Exception subclasses, and would encourage anyone interested in improving it by editing the wiki:</p>
<p><a href="http://redmine.ruby-lang.org/wiki/ruby/ExceptionClassesDoc" class="external">http://redmine.ruby-lang.org/wiki/ruby/ExceptionClassesDoc</a></p>
<p>Thanks.<br>
=end</p> Ruby 1.8 - Bug #2107 (Closed): Matrix: 1/any_matrix bug (fixed)https://bugs.ruby-lang.org/issues/21072009-09-17T13:43:19Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin</p>
<blockquote>
<p>ruby -r matrix -e "p 1/Matrix<a class="wiki-page new" href="https://bugs.ruby-lang.org/projects/ruby-18/wiki/1">1</a>"</p>
</blockquote>
<p>/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/matrix.rb:931:in <code>/': undefined local variable or method </code>_M' for #<Matrix::Scalar:0x1001199b8 @value=1> (NameError)<br>
from -e:1</p>
<p>Fixed in revision 24953</p>
<p><a href="http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=24953" class="external">http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=24953</a><br>
=end</p>