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 #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 #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 #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 #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 #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 #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 #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 #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 #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 #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 #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 #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 #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 #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 #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 #6538 (Rejected): Mutability of Rational and Complexhttps://bugs.ruby-lang.org/issues/65382012-06-03T07:20:46Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I hesitated to report this, but there is a "hole" in the immutability of Rational & Complex:</p>
<pre><code>r = Rational(0) # Rationals are immutable
r.freeze # but let's be certain and freeze it!
magic_trick(r) # r is now changed:
r # => (1/42)
</code></pre>
<p>The same thing occurs with Complex. I've left out the definition of <code>magic_trick</code> for anyone who wants to try and figure it out, but it's here: <a href="http://pastie.org/4016117" class="external">http://pastie.org/4016117</a></p>
<p>Is this worth fixing?</p> 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 #6086 (Rejected): Number of arguments and named parametershttps://bugs.ruby-lang.org/issues/60862012-02-25T16:30:57Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>While working on the messages of "wrong number of arguments" error (see <a class="issue tracker-1 status-5 priority-4 priority-default closed" title="Bug: Treatment of Wrong Number of Arguments (Closed)" href="https://bugs.ruby-lang.org/issues/6085">#6085</a>), I realized that the new named parameter feature can lead to misleading error messages:</p>
<p>def foo(x: 42)<br>
end</p>
<p>arg = {x: :bar}<br>
foo(arg) # => nil (no error)<br>
arg = :bar<br>
foo(arg) # => ArgumentError: wrong number of arguments (1 for 0)</p>
<p>It would be better if the wording was changed for methods accepting options. Maybe something like:</p>
<p>foo(arg) # => ArgumentError: wrong number of arguments (1 for 0 **)</p>
<p>Suggestions?</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 #3448 (Rejected): broken iconv libraryhttps://bugs.ruby-lang.org/issues/34482010-06-17T13:08:27Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Texts longer than ~8160 characters can create problems with iconv on some distributions:</p>
<p>require 'iconv'<br>
Iconv.conv("iso-8859-1//ignore", "utf-8", "\305\253" + "a"*8159).size #=> 8159<br>
Iconv.conv("iso-8859-1//ignore", "utf-8", "\305\253" + "a"*8160).size # => Iconv::IllegalSequence: "a"</p>
<p>The code above is from Debian 4 and 5 (on Heroku...), but it works as expected on OS X. As such, it affects Ruby 1.8 and 1.9</p>
<p>A google search reassured me I was not crazy, e.g. my_iconv_open in:<br>
<a href="http://www.opensource.apple.com/source/vim/vim-6/vim/src/mbyte.c" class="external">http://www.opensource.apple.com/source/vim/vim-6/vim/src/mbyte.c</a></p>
<a name="I-realize-this-is-somewhat-a-third-party-issue-but-Im-logging-this-nevertheless-as-a-brave-soul-might-bypass-the-bug-in-the-Ruby-library-andor-report-this-to-the-proper-authorities"></a>
<h2 >I realize this is somewhat a third party issue, but I'm logging this nevertheless, as a brave soul might bypass the bug in the Ruby library and/or report this to the proper authorities.<a href="#I-realize-this-is-somewhat-a-third-party-issue-but-Im-logging-this-nevertheless-as-a-brave-soul-might-bypass-the-bug-in-the-Ruby-library-andor-report-this-to-the-proper-authorities" class="wiki-anchor">¶</a></h2>
<p>Marc-André<br>
=end</p> Ruby master - Bug #3352 (Rejected): Delegates: protected methodshttps://bugs.ruby-lang.org/issues/33522010-05-27T15:55:26Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
require 'delegate'</p>
<pre><code> class X
protected
def pro
:foo
end
end
obj = X.new
obj.pro #=> NoMethodError: protected method `pro' called for #<X:0x000001008a2a68>
SimpleDelegator.new(obj).pro #=> :foo
</code></pre>
<p>I feel it would be more sensible to raise a NoMethodError.</p>
<p>No test seem to be testing for protected access, nor does RubySpec.</p>
<p>Unless there is objection, I'll commit the following:</p>
<p>diff --git a/lib/delegate.rb b/lib/delegate.rb<br>
index f366091..93fbc37 100644<br>
--- a/lib/delegate.rb<br>
+++ b/lib/delegate.rb<br>
@@ -141,7 +141,7 @@ class Delegator < BasicObject<br>
def method_missing(m, *args, &block)<br>
target = self.<strong>getobj</strong><br>
begin</p>
<ul>
<li>
<pre><code> target.respond_to?(m) ? target.__send__(m, *args, &block) : super(m, *args, &block)
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> target.respond_to?(m) ? target.public_send(m, *args, &block) : super
</code></pre>
ensure<br>
$@.delete_if {|t| %r"\A#{Regexp.quote(<strong>FILE</strong>)}:#{<strong>LINE</strong>-2}:"o =~ t} if $@<br>
end<br>
=end</li>
</ul> 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 #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 #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 #3016 (Rejected): Enumerable#slice_before and duphttps://bugs.ruby-lang.org/issues/30162010-03-26T14:01:58Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
When writing the specs for slice_before, I was surprised that it doesn't call #dup.</p>
<p>class X<br>
def dup<br>
raise "Hi!"<br>
end<br>
end</p>
<p>[:foo].slice_before(X.new){}.to_a</p>
<a name="gt-foo-I-expected-it-to-raise"></a>
<h1 >==> [[:foo]], I expected it to raise<a href="#gt-foo-I-expected-it-to-raise" class="wiki-anchor">¶</a></h1>
<p>The implementation calls directly rb_obj_dup.</p>
<p>It's a minor issue, but would it not be best to call dup on the argument? Most special needs for #dup can be addressed by initialize_dup, but maybe there are some reasonable cases where some user classes will redefine #dup?</p>
<p>The same question is valid for Enumerable#chunk.</p>
<p>diff --git a/enum.c b/enum.c<br>
index b69d8c9..e6e6adb 100644<br>
--- a/enum.c<br>
+++ b/enum.c<br>
@@ -14,7 +14,7 @@<br>
#include "node.h"</p>
<p>VALUE rb_mEnumerable;<br>
-static ID id_each, id_eqq, id_cmp, id_next, id_size;<br>
+static ID id_each, id_eqq, id_cmp, id_next, id_size, id_dup;</p>
<p>static VALUE<br>
enum_values_pack(int argc, VALUE *argv)<br>
@@ -2189,7 +2189,7 @@ chunk_i(VALUE yielder, VALUE enumerator, int argc, VALUE *argv)<br>
arg.yielder = yielder;</p>
<pre><code> if (!NIL_P(arg.state))
</code></pre>
<ul>
<li>
<pre><code> arg.state = rb_obj_dup(arg.state);
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> arg.state = rb_funcall(arg.state, id_dup, 0, 0);
</code></pre>
<p>rb_block_call(enumerable, id_each, 0, 0, chunk_ii, (VALUE)&arg);<br>
if (!NIL_P(arg.prev_elts))<br>
@@ -2364,7 +2364,7 @@ slicebefore_i(VALUE yielder, VALUE enumerator, int argc, VALUE *argv)<br>
arg.yielder = yielder;</p>
<p>if (!NIL_P(arg.state))</p>
</li>
</ul>
<ul>
<li>
<pre><code> arg.state = rb_obj_dup(arg.state);
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> arg.state = rb_funcall(arg.state, id_dup, 0, 0);
</code></pre>
<p>rb_block_call(enumerable, id_each, 0, 0, slicebefore_ii, (VALUE)&arg);<br>
if (!NIL_P(arg.prev_elts))<br>
@@ -2606,5 +2606,6 @@ Init_Enumerable(void)<br>
id_cmp = rb_intern("<=>");<br>
id_next = rb_intern("next");<br>
id_size = rb_intern("size");</p>
</li>
<li>
<p>id_dup = rb_intern("dup");<br>
}<br>
=end</p>
</li>
</ul> 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 #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 master - Bug #2770 (Closed): Matrix: determinant for rectangular matrices should raise an er...https://bugs.ruby-lang.org/issues/27702010-02-21T04:46:28Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Keiju,</p>
<p>$ rubydev -r matrix -e "puts Matrix[[1], [2], [3]].determinant"<br>
0</p>
<p>This corresponds to the documentation, but is not mathematically valid, since the determinant for rectangular matrices is not defined (at least for now! <a href="http://bit.ly/bwW7Gs" class="external">http://bit.ly/bwW7Gs</a> )</p>
<p>I believe an error should be thrown, similar to:<br>
$ rubydev -r matrix -e "puts Matrix[[1], [2], [3]].trace"<br>
/usr/local/rubydev/lib/ruby/1.9.1/matrix.rb:837:in <code>trace': Matrix dimension mismatch (ExceptionForMatrix::ErrDimensionMismatch) from -e:1:in </code>'</p>
<p>Since this is an API change, I attached a patch and will wait for your approval before committing.<br>
=end</p> Ruby master - Bug #2601 (Closed): BasicObject.initialize should raise an errorhttps://bugs.ruby-lang.org/issues/26012010-01-13T11:55:19Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
While having fun cloning BasicObject (see issue 2443), I found the amusing bug that :initialize could successfully be sent to BasicObject, creating all sorts of havoc.</p>
<p>$ rubydev -e "BasicObject.send :initialize; puts Object.ancestors" # => Loops indefinitely</p>
<p>$ rubydev -e "BasicObject.send :initialize, String; puts 42.upcase" # => Segmentation Fault</p>
<p>It was even possible to change the root of all Ruby classes without running into trouble:<br>
$ rubydev -e '<br>
SuperBasicObject = BasicObject.clone<br>
BasicObject.send :initialize, SuperBasicObject<br>
puts BasicObject.superclass<br>
'</p>
<a name="gt-SuperBasicObject"></a>
<h1 >==> SuperBasicObject<a href="#gt-SuperBasicObject" class="wiki-anchor">¶</a></h1>
<p>I fixed it, although changes might be required depending on the outcome of issue #2443.<br>
=end</p> Ruby master - Bug #2499 (Closed): InstructionSequence.dissassemble can crashhttps://bugs.ruby-lang.org/issues/24992009-12-19T11:52:54Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
I was trying to understand what InstructionSequence.disassemble is supposed to do when:</p>
<p>$ rubydev -e 'RubyVM::InstructionSequence.disassemble("x".method(:upcase))'<br>
-e:1: [BUG] Segmentation fault<br>
ruby 1.9.2dev (2009-12-19 trunk 26121) [x86_64-darwin10.2.0]</p>
<h2>-- control frame ----------<br>
c:0004 p:---- s:0010 b:0010 l:000009 d:000009 CFUNC :disassemble<br>
c:0003 p:0027 s:0006 b:0006 l:0022c8 d:001e98 EVAL -e:1<br>
c:0002 p:---- s:0004 b:0004 l:000003 d:000003 FINISH<br>
c:0001 p:0000 s:0002 b:0002 l:0022c8 d:0022c8 TOP</h2>
<p>-e:1:in <code><main>' -e:1:in </code>disassemble'</p>
<p>-- C level backtrace information -------------------------------------------</p>
<p>[NOTE]<br>
You may have encountered a bug in the Ruby interpreter or extension libraries.<br>
Bug reports are welcome.<br>
For details: <a href="http://www.ruby-lang.org/bugreport.html" class="external">http://www.ruby-lang.org/bugreport.html</a></p>
<p>Abort trap<br>
=end</p> Ruby master - Bug #2497 (Closed): Matrix: Vector#each2 with no block returns unusable enumeratorhttps://bugs.ruby-lang.org/issues/24972009-12-19T11:04:05Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Fixed in r26125<br>
=end</p> Ruby master - Bug #2496 (Closed): Delegate: #methods and #public_methods should return delegated ...https://bugs.ruby-lang.org/issues/24962009-12-19T10:38:20Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
require 'delegate'<br>
s = SimpleDelegator.new "Hello, world!"<br>
s.respond_to? :upcase # => true<br>
s.method :upcase # => #<Method : SimpleDelegator#upcase><br>
s.methods.include? :upcase # => false, true expected</p>
<p>Similar problem with public_methods.<br>
I propose that they return the union of methods from the delegator object and the methods of the object delegated to (only the public ones, since other ones are not forwarded)</p>
<p>Patch:<br>
diff --git a/lib/delegate.rb b/lib/delegate.rb<br>
index 77804e4..2fd5b49 100644<br>
--- a/lib/delegate.rb<br>
+++ b/lib/delegate.rb<br>
@@ -158,6 +158,22 @@ class Delegator<br>
end</p>
<pre><code>#
</code></pre>
<ul>
<li>
<a name="Returns-the-methods-available-to-this-delegate-object-as-the-union"></a>
<h1 >Returns the methods available to this delegate object as the union<a href="#Returns-the-methods-available-to-this-delegate-object-as-the-union" class="wiki-anchor">¶</a></h1>
</li>
<li>
<a name="of-this-objects-methods-and-the-public-methods-of-__getobj__"></a>
<h1 >of this object's methods and the public methods of __getobj__.<a href="#of-this-objects-methods-and-the-public-methods-of-__getobj__" class="wiki-anchor">¶</a></h1>
</li>
<li>
<h1></h1>
</li>
<li>def methods</li>
<li>self.<strong>getobj</strong>.public_methods | super</li>
<li>end</li>
<li>
<li>
<h1></h1>
</li>
<li>
<a name="Returns-the-methods-available-to-this-delegate-object-as-the-union-of-this-object"></a>
<h1 >Returns the methods available to this delegate object as the union of this object<a href="#Returns-the-methods-available-to-this-delegate-object-as-the-union-of-this-object" class="wiki-anchor">¶</a></h1>
</li>
<li>
<a name="and-the-methods-of-__getobj__"></a>
<h1 >and the methods of __getobj__.<a href="#and-the-methods-of-__getobj__" class="wiki-anchor">¶</a></h1>
</li>
<li>
<h1></h1>
</li>
<li>def public_methods(all=true)</li>
<li>self.<strong>getobj</strong>.public_methods(all) | super</li>
<li>end</li>
<li>
<li>
<h1></h1>
<a name="Returns-true-if-two-objects-are-considered-same"></a>
<h1 >Returns true if two objects are considered same.<a href="#Returns-true-if-two-objects-are-considered-same" class="wiki-anchor">¶</a></h1>
<h1></h1>
def ==(obj)<br>
=end</li>
</ul> Ruby master - Bug #2495 (Closed): Matrix: Vector#each2 should check its argumenthttps://bugs.ruby-lang.org/issues/24952009-12-19T10:35:22Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
$ rubydev -r matrix -e 'p Vector[*1..4].each2(nil){|x, y| p "#{x}, #{y}"}'<br>
/usr/local/rubydev/lib/ruby/1.9.1/matrix.rb:1149:in <code>each2': undefined method </code>size' for nil:NilClass (NoMethodError)</p>
<p>$ rubydev -r matrix -e 'p Vector[*1..4].each2(42){|x, y| p "#{x}, #{y}"}'<br>
/usr/local/rubydev/lib/ruby/1.9.1/matrix.rb:1149:in <code>each2': Vector dimension mismatch (ExceptionForMatrix::ErrDimensionMismatch) from -e:1:in </code>'</p>
<p>$ rubydev -r matrix -e 'p Vector[*1..8].each2(42){|x, y| p "#{x}, #{y}"}'<br>
"1, 0"<br>
"2, 1"<br>
"3, 0"<br>
"4, 1"<br>
"5, 0"<br>
"6, 1"<br>
"7, 0"<br>
"8, 0"</p>
<p>(or vice versa, if on a 32 bit platform)<br>
=end</p> Ruby master - Bug #2365 (Closed): Matrix: poor handling of coercion errors [patch]https://bugs.ruby-lang.org/issues/23652009-11-14T10:35:04Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
rubydev -r matrix -e 'p Matrix.I(2) - nil'<br>
/usr/local/rubydev/lib/ruby/1.9.1/matrix.rb:533:in <code>-': undefined method </code>coerce' for nil:NilClass (NoMethodError)<br>
from -e:1:in `'</p>
<p>Expected:<br>
some_where_in_the/matrix.rb:in <code>-': nil can't be coerced into Matrix (TypeError) from -e:1:in </code>'</p>
<p>Same situation with Vector.</p>
<p>I'd be grateful if you could confirm the attached patch is ok.<br>
=end</p> Ruby master - Bug #2330 (Closed): Non systematic segmentation fault with autoload rubyspechttps://bugs.ruby-lang.org/issues/23302009-11-04T14:36:10Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Starting from r25601, the following rubyspec will crash about half of the time (just repeat a couple of times):</p>
<p>$ mspec -t rubydev core/kernel/autoload_spec.rb<br>
ruby 1.9.2dev (2009-11-04 trunk 25641) [x86_64-darwin10.0.0]<br>
.........../Users/work/mspec/lib/mspec/mocks/proxy.rb:8: [BUG] Segmentation fault<br>
ruby 1.9.2dev (2009-11-04 trunk 25641) [x86_64-darwin10.0.0]</p>
<p>-- control frame ----------<br>
c:0036 p:0024 s:0121 b:0121 l:000120 d:000120 METHOD /Users/work/mspec/lib/mspec/mocks/proxy.rb:8<br>
c:0035 p:---- s:0115 b:0115 l:000114 d:000114 FINISH<br>
c:0034 p:---- s:0113 b:0113 l:000112 d:000112 CFUNC :autoload<br>
c:0033 p:0057 s:0108 b:0108 l:000208 d:000107 BLOCK /Users/work/ruby/dev/spec/rubyspec/core/kernel/autoload_spec.rb:105<br>
c:0032 p:---- s:0105 b:0105 l:000104 d:000104 FINISH<br>
c:0031 p:---- s:0103 b:0103 l:000102 d:000102 CFUNC :instance_eval<br>
c:0030 p:0017 s:0100 b:0100 l:000099 d:000099 METHOD /Users/work/mspec/lib/mspec/runner/mspec.rb:67<br>
c:0029 p:0021 s:0094 b:0094 l:000081 d:000093 BLOCK /Users/work/mspec/lib/mspec/runner/context.rb:135<br>
c:0028 p:---- s:0091 b:0091 l:000090 d:000090 FINISH<br>
c:0027 p:---- s:0089 b:0089 l:000084 d:000088 IFUNC :instance_variable_get<br>
c:0026 p:---- s:0087 b:0087 l:000086 d:000086 CFUNC :each<br>
c:0025 p:---- s:0085 b:0085 l:000084 d:000084 CFUNC :all?<br>
c:0024 p:0053 s:0082 b:0082 l:000081 d:000081 METHOD /Users/work/mspec/lib/mspec/runner/context.rb:135<br>
c:0023 p:0101 s:0076 b:0076 l:000065 d:000075 BLOCK /Users/work/mspec/lib/mspec/runner/context.rb:163<br>
c:0022 p:---- s:0071 b:0071 l:000070 d:000070 FINISH<br>
c:0021 p:---- s:0069 b:0069 l:000068 d:000068 CFUNC :each<br>
c:0020 p:0127 s:0066 b:0066 l:000065 d:000065 METHOD /Users/work/mspec/lib/mspec/runner/context.rb:155<br>
c:0019 p:0109 s:0063 b:0063 l:000062 d:000062 METHOD /Users/work/mspec/lib/mspec/runner/mspec.rb:36<br>
c:0018 p:0029 s:0056 b:0056 l:000055 d:000055 METHOD /Users/work/mspec/lib/mspec/runner/object.rb:11<br>
c:0017 p:0167 s:0049 b:0049 l:000208 d:000208 TOP /Users/work/ruby/dev/spec/rubyspec/core/kernel/autoload_spec.rb:69<br>
c:0016 p:---- s:0047 b:0047 l:000046 d:000046 FINISH<br>
</p>
<p>mspec version: 1.5.12<br>
rubyspec: current<br>
=end</p> Ruby master - Bug #2311 (Closed): [BUG] cfp consistency error - sendhttps://bugs.ruby-lang.org/issues/23112009-10-30T12:15:55Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Following r25521:</p>
<p>$rubydev -e '<br>
class X<br>
def method_missing(s); end<br>
end<br>
X.new.foo(:bar) rescue nil<br>
puts "hello"<br>
'</p>
<p>Generates<br>
-e:0:in <code>method_missing': wrong number of arguments (2 for 1) (ArgumentError) from -e:5:in </code>'<br>
Instead of "hello"</p>
<p>$ mspec core/file/stat/directory_spec.rb -t rubydev<br>
crashes ruby with [BUG] cfp consistency error - send<br>
=end</p> Ruby master - Bug #2276 (Closed): Array#<=> should not raise when comparison failshttps://bugs.ruby-lang.org/issues/22762009-10-26T20:03:17Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Since the addition of Object#<=>, the only comparison that raised an error was Array#<=>(not_an_array).</p>
<p>Array#<=>(obj) now returns nil if obj is not array-like.</p>
<p>Maybe this should also be applied in the 1.8 line?</p>
<p>Note: neither test-all nor rubyspec were testing for this.<br>
=end</p> Ruby master - Bug #2224 (Closed): lib/delegate: operator delegationhttps://bugs.ruby-lang.org/issues/22242009-10-17T13:15:20Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
The operators ==, =~, !~ are forwarded by Delegate. I presume the operators != and ~, new in 1.9, have simply been forgotten?</p>
<p>As for eql? and hash, this is probably intentional. I am still curious as to why, since this can yield surprising results (at least to me):</p>
<p>a = "foo"<br>
a1 = SimpleDelegator.new(a)<br>
a2 = a1.dup<br>
h = {}<br>
h[a] = :bar<br>
h[a1] = :bar<br>
h[a2] = :bar<br>
h # ==> {"foo"=>:bar, "foo"=>:bar, "foo"=>:bar}<br>
=end</p> Ruby master - Bug #2223 (Closed): lib/delegate: security model?https://bugs.ruby-lang.org/issues/22232009-10-17T12:39:33Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Take the following code:</p>
<p>require 'delegate'<br>
cat = "cat"<br>
dog = SimpleDelegator.new("dog")</p>
<p>cat.untrust<br>
dog.untrust</p>
<p>lambda {$SAFE = 4; cat.upcase!}.call # ==> "CAT"<br>
lambda {$SAFE = 4; dog.upcase!}.call # ==> Security Error</p>
<p>Is that expected?</p>
<p>Maybe #trust, #untrust, #taint and #untaint should both call 'super' and forward the call to <strong>getobj</strong>?</p>
<p>I'm even less sure as to what to do with #tainted? and #untrusted? for mixed cases (i.e. when self and <strong>getobj</strong> have different taintedness/trust). Disallow these cases? return "super || <strong>getobj</strong>.tainted?" ?<br>
=end</p> Ruby master - Bug #2221 (Closed): lib/delegate: freeze has odd effectshttps://bugs.ruby-lang.org/issues/22212009-10-16T15:43:36Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Freeze doesn't quite freeze, and can't be cloned:</p>
<p>require 'delegate'<br>
d = SimpleDelegator.new([1,2,3])<br>
d.freeze<br>
d[0] = :hello; d # ==> [:hello, 2, 3], I expected a runtime error<br>
d.clone # ==> RuntimeError, I expected some kind of copy of d</p>
<p>Maybe #freeze and #frozen should be forwarded:</p>
<p>diff --git a/lib/delegate.rb b/lib/delegate.rb<br>
index 57c479c..f4bd453 100644<br>
--- a/lib/delegate.rb<br>
+++ b/lib/delegate.rb<br>
@@ -115,7 +115,7 @@</p>
<a name="implementation-see-SimpleDelegator"></a>
<h1 >implementation, see SimpleDelegator.<a href="#implementation-see-SimpleDelegator" class="wiki-anchor">¶</a></h1>
<h1></h1>
<p>class Delegator</p>
<ul>
<li>[:to_s,:inspect,:=~,:!~,:===].each do |m|</li>
</ul>
<ul>
<li>[:to_s,:inspect,:=~,:!~,:===, :freeze, :frozen?].each do |m|<br>
undef_method m<br>
end</li>
</ul>
<p>But maybe the Delegator itself should also be frozen? I mean should a call to #<strong>setobj</strong> raise a runtime error or not?</p>
<p>Also, there are other methods that should probably be forwarded (eql?, hash, etc...); see issue <a class="issue tracker-2 status-6 priority-4 priority-default closed" title="Feature: Delegator < BasicObject (Rejected)" href="https://bugs.ruby-lang.org/issues/1333">#1333</a>.<br>
=end</p> Ruby master - Bug #2207 (Closed): lib/delegate: #method doesn't delegate to its objecthttps://bugs.ruby-lang.org/issues/22072009-10-14T13:45:55Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
require 'delegate'<br>
d = SimpleDelegator.new("hello")<br>
d.method(:upcase) # ==> NameError: undefined method <code>upcase' for class </code>SimpleDelegator'</p>
<p>Note that in Ruby 1.8, this does not create an error.<br>
This is fixed by defining respond_to_missing? instead of respond_to?</p>
<p>diff --git a/lib/delegate.rb b/lib/delegate.rb<br>
index 57c479c..6b9f91a 100644<br>
--- a/lib/delegate.rb<br>
+++ b/lib/delegate.rb<br>
@@ -143,12 +143,11 @@ class Delegator<br>
end</p>
<pre><code>#
</code></pre>
<ul>
<li>
<a name="Checks-for-a-method-provided-by-this-the-delegate-object-by-fowarding-the"></a>
<h1 >Checks for a method provided by this the delegate object by fowarding the<a href="#Checks-for-a-method-provided-by-this-the-delegate-object-by-fowarding-the" class="wiki-anchor">¶</a></h1>
</li>
</ul>
<ul>
<li>
<a name="Checks-for-a-method-provided-by-this-the-delegate-object-by-forwarding-the"></a>
<h1 >Checks for a method provided by this the delegate object by forwarding the<a href="#Checks-for-a-method-provided-by-this-the-delegate-object-by-forwarding-the" class="wiki-anchor">¶</a></h1>
<a name="call-through-__getobj__"></a>
<h1 >call through __getobj__.<a href="#call-through-__getobj__" class="wiki-anchor">¶</a></h1>
<h1></h1>
</li>
</ul>
<ul>
<li>def respond_to?(m, include_private = false)</li>
<li>return true if super</li>
<li>return self.<strong>getobj</strong>.respond_to?(m, include_private)</li>
</ul>
<ul>
<li>def respond_to_missing?(m, include_private = false)</li>
<li>
<strong>getobj</strong>.respond_to?(m, include_private)<br>
end</li>
</ul>
<pre><code>#
</code></pre>
<p>Only caveat is that after a change of object of different class, the method can produce a NoMethodError when called. (same as Ruby 1.8)<br>
Any objection?<br>
=end</p> Ruby master - Bug #2206 (Closed): lib/delegate: inconsistency between respond_to? and sendhttps://bugs.ruby-lang.org/issues/22062009-10-14T13:06:05Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
require 'delegate'<br>
class A<br>
private<br>
def private_method<br>
:bar<br>
end<br>
end</p>
<p>x = SimpleDelegator.new(A.new)<br>
x.respond_to?(:private_method, true) # ==> true<br>
x.send(:private_method) # ==> NoMethodError</p>
<p>I expected the call to private_method to be delegated. The attached patch fixes the problem. It is not very elegant but I couldn't think of anything better.<br>
=end</p> Ruby master - Bug #2199 (Closed): Object#method should call respond_to_missing?(sym, true)https://bugs.ruby-lang.org/issues/21992009-10-13T14:16:43Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Is there any reason I'm missing?</p>
<p>class A<br>
def respond_to_missing?(method, private = false)<br>
method == :is_private && private<br>
end</p>
<pre><code> def is_private2
end
private :is_private2
</code></pre>
<p>end</p>
<p>A.new.method(:is_private2) # ==> #<Method: A#is_private2>...<br>
A.new.method(:is_private) # ==> NameError: undefined method <code>is_private' for class </code>A'</p>
<p>If not:</p>
<p>diff --git a/proc.c b/proc.c<br>
index 5ed3c01..b7c632c 100644<br>
--- a/proc.c<br>
+++ b/proc.c<br>
@@ -902,7 +902,7 @@ mnew(VALUE klass, VALUE obj, ID id, VALUE mclass, int scope)<br>
VALUE sym = ID2SYM(id);</p>
<pre><code> if (obj != Qundef && !rb_method_basic_definition_p(klass, rmiss)) {
</code></pre>
<ul>
<li>
<pre><code> if (RTEST(rb_funcall(obj, rmiss, 1, sym))) {
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> if (RTEST(rb_funcall(obj, rmiss, 2, sym, Qtrue))) {
def = ALLOC(rb_method_definition_t);
def->type = VM_METHOD_TYPE_MISSING;
def->original_id = id;
</code></pre>
</li>
</ul>
<p>=end</p> Ruby master - Bug #2189 (Closed): Math.atanh(1) & Math.atanh(-1) should not raise an errorhttps://bugs.ruby-lang.org/issues/21892009-10-10T14:53:28Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Regression caught by RubySpec.</p>
<p>$ rubydev -v -e 'p Math.atanh(1)'<br>
ruby 1.9.2dev (2009-10-09 trunk 25274) [x86_64-darwin10.0.0]<br>
-e:1:in <code>atanh': Numerical argument out of domain - atanh (Errno::EDOM) from -e:1:in </code>'<br>
$ ruby187 -v -e 'p Math.atanh(1)'<br>
ruby 1.8.7 (2008-08-11 patchlevel 72) [universal-darwin10.0]<br>
Infinity</p>
<p>Fixed in r25279<br>
=end</p> Ruby master - Bug #2140 (Closed): Bignum#** broken by lib/mathnhttps://bugs.ruby-lang.org/issues/21402009-09-24T09:37:35Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
ruby -r mathn -e 'p (1<<66)**2'<br>
/usr/local/ruby19/lib/ruby/1.9.1/mathn.rb:50:in <code>**': undefined method </code>power!' for 73786976294838206464:Bignum (NoMethodError)<br>
from -e:1:in `'</p>
<p>Fixed in r25067<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> Ruby master - Bug #1885 (Closed): Proper comparison of recursive Struct & Rangehttps://bugs.ruby-lang.org/issues/18852009-08-05T05:30:15Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
The following code freezes the latest ruby 1.9:</p>
<p>MyClass = Struct.new(:foo)<br>
x = MyClass.new; x[:foo] = x<br>
y = MyClass.new; y[:foo] = y<br>
x == y # Loops forever (can not be interrupted)</p>
<p>Solution: rb_struct_equal & rb_struct_eql should handle recursion in a similar fashion as Array and Hash (i.e. by calling rb_exec_recursive_paired and returning Qtrue if recursion is detected). I could make a patch if needed.</p>
<p>Searching the source code for rb_exec_recursive revealed that Range is potentially recursive too (see range_inspect). The ==, eql? and === methods do not call rb_exec_recursive_paired and are thus also potentially troublesome. To build a recursive Range is not trivial though; either some intermediate container class is needed or else some crazy thing like:</p>
<p>class CrazyRange < Range<br>
def initialize<br>
super(self..self)<br>
end</p>
<pre><code> def <=>(x)
0 # Needed so CrazyRange can be the begin and end values of a range...
end
</code></pre>
<p>end</p>
<p>CrazyRange.new == CrazyRange.new # Loops forever (can not be interrupted)</p>
<p>I'm not sure that it is worth modifying ==, eql? and === to use rb_exec_recursive_paired and make them bulletproof.</p>
<p>Note that both Struct#hash and Range#hash face the same issue than Array#hash & Hash#hash (see issue <a class="issue tracker-1 status-5 priority-4 priority-default closed" title="Bug: Enumerable's #hash Raises ArgumentError When Recursive Values are Present (Closed)" href="https://bugs.ruby-lang.org/issues/1852">#1852</a>)<br>
=end</p> Ruby master - Bug #1686 (Closed): Enumerable#first brokenhttps://bugs.ruby-lang.org/issues/16862009-06-25T03:25:09Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Enumerable#first is broken in the current HEAD. If 4 <= n < enum_length + 4, enum.first(n) returns the (n-4)th element instead of an array of n elements. E.g.:</p>
<p>to6 = (1..6).to_enum # necessary so Enumerable#first is used<br>
p to6.first(2) # ==> [1, 2]<br>
p to6.first(4) # ==> 1<br>
p to6.first(9) # ==> 6<br>
p to6.first(10) # ==> [1, 2, 3, 4, 5, 6]</p>
<p>This is due to <a href="http://redmine.ruby-lang.org/repositories/diff/ruby-19/enum.c?rev=23622" class="external">http://redmine.ruby-lang.org/repositories/diff/ruby-19/enum.c?rev=23622</a> , after which ary[0] holds "n" as a long instead of a Fixnum. The comparison to Qnil isn't working as desired.</p>
<p>Either ary[0] holds INT2NUM(len) and first_i calls NUM2LONG + INT2NUM (as per my original patch, see <a href="http://redmine.ruby-lang.org/issues/show/1554" class="external">http://redmine.ruby-lang.org/issues/show/1554</a> ) or alternatively, enum_first could use take_i or enum_take when there is an argument, since they behave the same way in that case.<br>
=end</p> Ruby master - Bug #1666 (Closed): Confusion in documentation for lines vs each_line, etc...https://bugs.ruby-lang.org/issues/16662009-06-20T21:44:22Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Currently, IO#lines is defined as "to_enum(:each_line, *args)" and thus will ignore a block if one is given.<br>
On the other hand, String#lines and String#each_line are aliases, and thus will both execute the block, if one given. The same is true for StringIO#lines and StringIO#each_line.</p>
<p>The same distinction exist in IO for #bytes vs #each_byte, #chars vs #each_char, while these pairs are aliases in String and StringIO.</p>
<p>To add to the confusion, the documentation is different for String#lines vs String#each_line, #bytes vs #each_byte, #chars vs #each_char (although they are aliases). StringIO#bytes, #lines & #chars are not documented at all.</p>
<p>So either:</p>
<ol>
<li>there should not be a distinction (and IO's implementation and doc should be changed to reflect that)<br>
or 2) the distinction is intentional (and String + StringIO's implementation should be changed to relect that)<br>
or 3) there is a compelling reason why the behavior in IO should be different than in String and StringIO and that should be spelled out in the doc.</li>
</ol>
<p>In all cases, the documentation for String should be cleaned up; for example String#each_char doesn't state that an enumerator is returned if no block is given (contrary to the doc for String#chars) and the examples are wrong since they use #each (which no longer exists) instead of #each_char.</p>
<p>Finally, the pair #codepoints and #each_codepoint is in a similar mismatch of documentation in String. I'll post a separate feature request to add IO#codepoints, etc...<br>
=end</p> Ruby master - Bug #1665 (Closed): Enumerable#reverse_each, #entries, #to_a documentation [patch]https://bugs.ruby-lang.org/issues/16652009-06-20T20:40:16Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
The following are missing from the 1.8.7 release News:<br>
Enumerable#reverse_each (new method)<br>
Enumerable#to_a, #entries (takes optional arguments)</p>
<p>Since the 1.9 release News refer to the 1.8.7 news, this fixes both 1.8.7 and 1.9 release news.</p>
<p>Moreover the documentation for Enumerable#to_a, #entries needs to be updated in both the 1.8.7 and 1.9 releases (patches for both included).<br>
=end</p> Ruby master - Bug #1664 (Closed): Kernel#define_singleton_method not documented [patch]https://bugs.ruby-lang.org/issues/16642009-06-20T19:58:49Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Kernel#define_singleton_method is currently missing its documentation.<br>
I propose the following:</p>
<p>call-seq:<br>
define_singleton_method(symbol, method) => new_method<br>
define_singleton_method(symbol) { block } => proc</p>
<p>Defines a singleton method in the receiver. The <em>method</em><br>
parameter can be a +Proc+ or +Method+ object.<br>
If a block is specified, it is used as the method body. This block<br>
is evaluated using <code>instance_eval</code>.</p>
<pre><code>class A
class << self
def class_name
to_s
end
end
end
A.define_singleton_method(:who_am_i) do
"I am: #{class_name}"
end
A.who_am_i # ==> "I am: A"
guy = "Bob"
guy.define_singleton_method(:hello) { "#{self}: Hello there!" }
guy.hello # => "Bob: Hello there!"
</code></pre>
<p>I've included the corresponding patch. This method should also be documented in the 1.8.7 branch.<br>
=end</p> Ruby master - Bug #1554 (Closed): Enumerator#first & #take should consume only what is needed [pa...https://bugs.ruby-lang.org/issues/15542009-06-02T05:38:59Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Currently, in Ruby 1.9.x:</p>
<p>require 'stringio'<br>
s = StringIO.new("first \n second \n third")</p>
<p>s.rewind<br>
p s.take(1), s.take(1)</p>
<a name="Prints-first-n-and-second-n"></a>
<h1 >Prints "[first \n]" and "[ second \n]"<a href="#Prints-first-n-and-second-n" class="wiki-anchor">¶</a></h1>
<p>s.rewind<br>
p [s.first], [s.first]</p>
<a name="Prints-first-n-and-second-n-2"></a>
<h1 >Prints "[first \n]" and "[ second \n]"<a href="#Prints-first-n-and-second-n-2" class="wiki-anchor">¶</a></h1>
<p>s.rewind<br>
p s.first(1), s.first(1)</p>
<a name="Prints-first-n-and-third"></a>
<h1 >Prints "[first \n]" and "[third]"<a href="#Prints-first-n-and-third" class="wiki-anchor">¶</a></h1>
<p>I believe most people would expect that [s.first], s.first(1) and s.take(1) should be the same and have the same side effects, if any. It is also more efficient that :each yields just the right number of times necessary to complete the request. As such it would be preferable if the last printout was the same as the previous two.</p>
<p>Note that in Ruby 1.8.7, the output for Enumerable#take is also wrong.</p>
<p>The included patches fix this issue for both versions.</p>
<p>I took the opportunity to change #first so that it calls :to_int on its argument only once if it needs to be converted. Before the patch it is called twice. This brings it in line with Array#first and Enumerable#take.</p>
<p>Note: rubyspecs have been updated.<br>
=end</p> Ruby master - Bug #1532 (Closed): Improved matrix.rb [patch]https://bugs.ruby-lang.org/issues/15322009-05-29T04:18:55Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
The fact that the 'matrix' library is included in Ruby is very helpful.<br>
There are currently some open bugs, and some improvements could make it easier to use.</p>
<p>Propositions:</p>
<ol>
<li>Matrix#trace should raise an ErrDimensionMismatch if the matrix is not square</li>
</ol>
<p>Mathematically speaking, the trace is only defined for square matrices (ref: wikipedia, mathworld)<br>
Currently, Matrix[[1,2]].trace raises a NoMethodError: undefined method `[]' for nil:NilClass<br>
Note that Matrix[[1,2]].transpose.trace returns 1, although in mathematically, trace(M) = trace(transpose(M))</p>
<p>Raising an ErrDimensionMismatch would bring #trace in line with #inverse</p>
<ol start="2">
<li>Matrix creation methods should perform checks and conversion so that values are stored as an Array of Arrays.</li>
</ol>
<p>Currently, no checking is done, so the following will all be constructed without an error or a warning:<br>
Matrix[:hello]<br>
Matrix[nil]<br>
Matrix[4], etc...</p>
<p>Later on, confusing results or strange errors will happen. E.g.:<br>
Matrix[42].transpose # ==> Matrix[[42], [0], [0], [0]]</p>
<p>A TypeError should be raised if the argument is not convertible to an Array of Arrays.</p>
<p>Moreover, non arrays that should be converted using :to_ary, to be consistent<br>
with the builtin library methods that accept array arguments (e.g. Array#transpose)</p>
<p>Finally, conversion from Vector to arrays should be always be performed. Currently,<br>
a = Matrix[[1,2],[3,4]] # => Matrix[[1, 2], [3, 4]]<br>
b = Matrix.rows([a.row(0), a.row(1)]) # => Matrix[Vector[1, 2], Vector[3, 4]]<br>
a == b # => false<br>
It would be more useful, intuitive and mathematically correct if a == b and b.to_s == "Matrix[[1, 2], [3, 4]]"</p>
<p>The same is true for Vector creation methods. For example currently:<br>
Vector.elements(42, false).size # ==> 4<br>
Vector.elements(Vector[1,2,3]) == Vector.elements([1,2,3]) # ==> false<br>
It would be more useful, intuitive and correct if the first example raises an error and the second returns true</p>
<ol start="3">
<li>Matrix creators should enforce that a matrix is rectangular.</li>
</ol>
<p>Currently, a matrix with irregular rows can be created, e.g. x = Matrix[[1,2],[3]].<br>
Mathematically speaking, that is not a matrix.<br>
Basically none of the Matrix methods are of any use for non-rectangular matrices.<br>
Moreover, many strange errors can occur later on. For example, x.inverse will<br>
raise a "NoMethodError: undefined method `*' for nil:NilClass"</p>
<p>It would be helpful to catch these cases at creation time.<br>
Many creation methods don't have to make any extra checks (e.g. Matrix.scalar), and<br>
all methods of Matrix can bypass this extra check when they have created the arrays themselves<br>
(e.g. Matrix#*). There would be a small cost for creation using Matrix.[] and Matrix.rows,<br>
although it is in O(rows) while most other operations are usually in O(rows x columns),<br>
so the performance difference would be minimal.</p>
<ol start="4">
<li>Matrix should deal with empty matrices.</li>
</ol>
<p>Currently, empty matrices like Matrix[] cause problem.<br>
For example Matrix[].determinant raises an error, so does Matrix[] * Matrix[].</p>
<p>Moreover, if h = Matrix[[], []], then currently h.transpose.transpose != h</p>
<p>While an alternative would be to raise and error, the best solution is to handle<br>
empty matrices properly, both 0x0, 0xn and nx0, as does MatLab, GNU Octave, etc...<br>
See doc and references to the literature in:<br>
<a href="http://www.gnu.org/software/octave/doc/interpreter/Empty-Matrices.html" class="external">http://www.gnu.org/software/octave/doc/interpreter/Empty-Matrices.html</a></p>
<ol start="5">
<li>Out of bound indices should be dealt with.</li>
</ol>
<p>a) Matrix#[row,col] should behave in a consisten way if either row or col is out of bounds.<br>
Currently it returns nil vs raises an obscure error (See redmine #1518.)</p>
<p>b) Matrix[[1]].row(2) raises an obscure error, while Matrix[[1]].column(2) returns Vector[nil, nil]</p>
<p>c) In a similar vein, Matrix[[1]].minor(2..2,1..1) currently raises an error but not<br>
Matrix[[1]].minor(1..1,2..2)</p>
<p>Solutions:<br>
a) To be consistent with array lookup using [], Matrix#[] should return nil for out of bounds elements.<br>
A #fetch method could be added, but the fact that matrices normally won't contain nil or false<br>
makes it easy to deal with out of bounds references, e.g. m[r, c] || 0</p>
<p>b) Contrary to nil, it is not easy nor useful to deal with Vector[nil, nil, ...].<br>
#row, and #column could raise an IndexError, but it is more useful and<br>
more coherent with Array#at, etc... to return nil.</p>
<p>c) The same way Matrix#row and #col can be related to Array#at,<br>
Matrix#minor should have similar semantics to Array#slice. If either starting point<br>
is out of bounds, nil is returned. Otherwise a Matrix is returned, although it can<br>
be smaller than what was requested. This is similar to<br>
[:a, :b].slice(3..10) # => nil<br>
[:a, :b].slice(2..10) # => []<br>
[:a, :b].slice(1..10) # => [:b]<br>
Matrix[[1], [2]].minor(0..10, 2..10) # => nil<br>
Matrix[[1], [2]].minor(0..10, 1..10) # => Matrix[[], []]<br>
Matrix[[1], [2]].minor(1..10, 0..10) # => Matrix[[2]]</p>
<ol start="6">
<li>Matrix#collect, Vector#collect, #collect2, #map2 should return enumerators if no block is given</li>
</ol>
<p>This would be more useful and is consistent with Array#each, etc...</p>
<ol start="7">
<li>Matrix#hash should have less collisions</li>
</ol>
<p>Currently, the following matrices have the same hash:<br>
Matrix[]<br>
Matrix[[0,0], [0,0]]<br>
Matrix[[1,0], [0,1]]<br>
Matrix[[42,42], [666,666]]<br>
Matrix[[1,2,3,4], [5,6,1,2], [3,4,5,6]]</p>
<p>Ideally, these should have different hashes, since they are different matrices.</p>
<ol start="8">
<li>Matrix#compare_by_row_vectors, Vector#compare_by and Vector#init_elements should be made private or disappear.</li>
</ol>
<p>As per the documentation, these are not meant to be used.<br>
As such it would be best if they didn't appear in the list of methods.</p>
<p>The attached patch addresses all these issues.</p>
<p>Moreover, it addresses all matrix-related issues I could find on redmine:<br>
<a href="http://redmine.ruby-lang.org/issues/show/1020" class="external">http://redmine.ruby-lang.org/issues/show/1020</a><br>
<a href="http://redmine.ruby-lang.org/issues/show/1515" class="external">http://redmine.ruby-lang.org/issues/show/1515</a><br>
<a href="http://redmine.ruby-lang.org/issues/show/1516" class="external">http://redmine.ruby-lang.org/issues/show/1516</a><br>
<a href="http://redmine.ruby-lang.org/issues/show/1517" class="external">http://redmine.ruby-lang.org/issues/show/1517</a><br>
<a href="http://redmine.ruby-lang.org/issues/show/1518" class="external">http://redmine.ruby-lang.org/issues/show/1518</a><br>
<a href="http://redmine.ruby-lang.org/issues/show/1526" class="external">http://redmine.ruby-lang.org/issues/show/1526</a><br>
<a href="http://redmine.ruby-lang.org/issues/show/1531" class="external">http://redmine.ruby-lang.org/issues/show/1531</a></p>
<p>Also fixed a bug with #determinant and #determinant_e that would raise an error for some matrices<br>
(for instance any square matrix with m[0][0] == 0, e.g. Matrix[[0,1],[2,3]].determinant # => error raised)</p>
<p>Finally, the following methods are performing faster:<br>
Matrix#collect<br>
Matrix#transpose<br>
Matrix#==<br>
Matrix#eql?<br>
Matrix#hash<br>
Vector#collect<br>
Vector#map2</p>
<p>Note that the branch 'runpaint' of rubyspecs has specs to this patch.<br>
=end</p> Ruby master - Bug #1531 (Closed): Matrix#determinant fails on some matriceshttps://bugs.ruby-lang.org/issues/15312009-05-29T04:17:19Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
ruby1.9 -r matrix -e 'Matrix[[0,1],[1,0]].determinant'<br>
/usr/local/ruby191/lib/ruby/1.9.1/matrix.rb:685:in <code>block (2 levels) in determinant': undefined method </code>+' for nil:NilClass (NoMethodError)<br>
from /usr/local/ruby191/lib/ruby/1.9.1/matrix.rb:684:in <code>loop' from /usr/local/ruby191/lib/ruby/1.9.1/matrix.rb:684:in </code>block in determinant'<br>
from /usr/local/ruby191/lib/ruby/1.9.1/matrix.rb:681:in <code>loop' from /usr/local/ruby191/lib/ruby/1.9.1/matrix.rb:681:in </code>determinant'<br>
from -e:1:in `'</p>
<p>Same with determinant_e.</p>
<p>To fix: gsub('ii','i') in matrix.rb<br>
=end</p> Ruby master - Bug #1510 (Closed): [patch] String#partition can return wrong result or crashhttps://bugs.ruby-lang.org/issues/15102009-05-25T07:36:38Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
The attached patch fixes a problem that occurs when the argument of String#partition needs to be converted using :to_str.</p>
<p>E.g:</p>
<p>class C<br>
def to_str<br>
"foo"<br>
end<br>
end<br>
p "foo-bar".partition(C.new)</p>
<p>Before patch:<br>
["", #<C:0x2c62a8>, "foo-bar"]</p>
<p>After patch:<br>
["", "foo", "-bar"]</p>
<p>RubySpecs has been updated. Without the version guard, it crashes Ruby.<br>
=end</p> Ruby master - Bug #1448 (Closed): [patch] Proper handling of recursive arrayshttps://bugs.ruby-lang.org/issues/14482009-05-09T11:47:45Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Dealing with recursive arrays & hashes can be tricky.</p>
<p>The current handling of recursive arrays is much improved over that of Ruby 1.8.6. Array comparison still has some bugs though.</p>
<p>For instance:<br>
x = []; x << x<br>
y = [[x]]<br>
x == y # ==> true<br>
y == x # ==> false, should be true!</p>
<p>Morevoer, recursive arrays that are built the same way are not recognized as equal:<br>
z = []; z << z<br>
x == z # ==> false, should be true!</p>
<p>Needless to say, arrays that have the same elements (e.g. a single element, containing a single element, ...) but built differently way are not recognized as equal:<br>
stone = []; stepping = [stone]; stone << stepping<br>
x == stepping # ==> false, would be nice to be true!</p>
<p>The attached patch fixes all of these problems :-)</p>
<ul>
<li>How:<br>
The function rb_exec_recursive handles the recursivity by pushing and poping the elements it encounters for a given method (for example eql?). For such comparisons, instead of keeping track of the elements it encounters, I modified it so that it keeps track of both the elements being compared. A recursion is detected only when a matching pair is found.</li>
</ul>
<p>This takes care of the first problem. For the next two, we only need to observe that if we have a recursion on the pair (x,y) when comparing x and y, then it is because they are not different! Changing the return value for recursive cases from nil (not comparable) / false (different) to Qundef (unknown yet) makes comparison of complex recursive "trees" work beautifully. I've added some cute samples in rubyspecs (core/array/shared/equal.rb)</p>
<ul>
<li>Implementation details:<br>
Previous recursive_push/pop/check maintained a hash of encountered object ids, setting hash[obj] = true. I modified them so that in "paired" cases, it sets hash[obj] = paired_obj. If a pair (obj, different_paired_obj) is encountered later on, I set hash[obj] to {paired_obj => true, different_paired_obj => true}.</li>
</ul>
<p>This way, there is basically no runtime cost to this technique, except in the complex recursive cases. Only for these complex cases is there a small additional cost for the hash creation/destruction.</p>
<ul>
<li>Last problem:<br>
There is one more problem that my patch doesn't cover (lack of mri-fu): hashes for recursive structures are incorrect. As per the official doc, "a.eql? b" should imply "a.hash == b.hash". On the other hand, we have (before or after my patch):<br>
a = [x]<br>
x.eql? a # ==> true<br>
a.eql? x # ==> true<br>
x.hash == a.hash # ==> false, should have same hash</li>
</ul>
<p>The solution is that when calculating the hash for an array, if a recursion is detected, then the hash should return a fixed value (say 0 or -length) <em>for the original</em> array. Currently, 0 is returned but at the level that the recursion is detected. In Ruby pseudo-code, it would look like:</p>
<pre><code> static VALUE
recursive_hash(VALUE ary, VALUE dummy, int recur)
{
long i, h;
VALUE n;
if (recur) {
</code></pre>
<ul>
<li>
<pre><code> raise HashingRecursionDetected
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> return LONG2FIX(0);
}
h = rb_hash_start(RARRAY_LEN(ary));
for (i=0; i<RARRAY_LEN(ary); i++) {
n = rb_hash(RARRAY_PTR(ary)[i]);
h = rb_hash_uint(h, NUM2LONG(n));
}
h = rb_hash_end(h);
return LONG2FIX(h);
</code></pre>
<p>}</p>
<p>static VALUE<br>
rb_ary_hash(VALUE ary)<br>
{<br>
return rb_exec_recursive(recursive_hash, ary, 0);</p>
</li>
</ul>
<ul>
<li>rescue HashingRecursionDetected</li>
<li>
<pre><code> return -length
</code></pre>
}</li>
</ul>
<p>A similar modification must be made for hash.c.</p>
<p>Thanks</p>
<p>Marc-André Lafortune<br>
=end</p> Ruby master - Bug #1440 (Closed): Array#flatten!(0) should return nil, not selfhttps://bugs.ruby-lang.org/issues/14402009-05-07T15:42:37Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
As per doc, flatten!(0) does not make modifications and should thus return nil.</p>
<p>[].flatten! # ==> nil<br>
[].flatten!(42) # ==> nil<br>
[].flatten!(-1) # ==> nil<br>
[].flatten!(0) # ==> []</p>
<p>Poor man's diff for "rb_ary_flatten_bang"</p>
<ul>
<li>
<pre><code>if (level == 0) return ary;
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code>if (level == 0) return Qnil;
</code></pre>
</li>
</ul>
<p>=end</p> Ruby master - Bug #1439 (Closed): Array#sample returns wrong results for negative argumenthttps://bugs.ruby-lang.org/issues/14392009-05-07T12:27:25Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
$ ruby1.9 -v -e "p [1,2].sample(-1)"<br>
ruby 1.9.2dev (2009-05-06 trunk 23352) [i386-darwin9.6.0]<br>
[1, 2, false]<br>
=end</p>