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 - Feature #17785 (Open): Allow named parameters to be keywordshttps://bugs.ruby-lang.org/issues/177852021-04-08T15:08:40Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>We should allow named parameters to be keywords and use add a trailing <code>_</code> to the corresponding variable:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">check</span><span class="p">(</span><span class="n">arg</span><span class="p">,</span> <span class="k">class</span><span class="p">:)</span>
<span class="n">arg</span><span class="p">.</span><span class="nf">is_a?</span><span class="p">(</span><span class="n">class_</span><span class="p">)</span>
<span class="k">end</span>
<span class="n">check</span><span class="p">(</span><span class="mi">42</span><span class="p">,</span> <span class="ss">class: </span><span class="no">Integer</span><span class="p">)</span> <span class="c1"># => true</span>
</code></pre>
<p>Currently, if we want such an API we have to use <code>**rest</code>:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">check</span><span class="p">(</span><span class="n">arg</span><span class="p">,</span> <span class="o">**</span><span class="n">rest</span><span class="p">)</span>
<span class="n">class_</span> <span class="o">=</span> <span class="n">rest</span><span class="p">.</span><span class="nf">fetch</span><span class="p">(</span><span class="ss">:class</span><span class="p">)</span> <span class="p">{</span> <span class="k">raise</span> <span class="no">ArgumentError</span><span class="p">(</span><span class="s1">'missing keyword: :class'</span><span class="p">)}</span>
<span class="k">if</span> <span class="n">rest</span><span class="p">.</span><span class="nf">size</span> <span class="o">></span> <span class="mi">1</span>
<span class="n">unknown</span> <span class="o">=</span> <span class="n">rest</span><span class="p">.</span><span class="nf">keys</span> <span class="o">-</span> <span class="p">[</span><span class="ss">:class</span><span class="p">]</span>
<span class="k">raise</span> <span class="no">ArgumentError</span><span class="p">(</span><span class="s2">"unknown keyword(s): :</span><span class="si">#{</span><span class="n">unknown</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="s1">', :'</span><span class="p">)</span><span class="si">}</span><span class="s2">)
end
arg.is_a?(class_)
end
</span></code></pre>
<p>This is very verbose, much less convenient, much less readable, prevents <code>steep</code> from generating the proper signature, etc.</p>
<p>We should do the same for pattern match.</p> Ruby master - Feature #17601 (Closed): lib/benchmark: adding `Benchmark::Tms#to_h`https://bugs.ruby-lang.org/issues/176012021-01-31T17:11:24Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>It seems useful to add <code>to_h</code> method to benchmark output.</p>
<p>I'll take care of that unless there's objection.</p>
<p>See <a href="https://github.com/ruby/benchmark/pull/4" class="external">https://github.com/ruby/benchmark/pull/4</a></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 #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 - Misc #17502 (Open): C vs Rubyhttps://bugs.ruby-lang.org/issues/175022021-01-02T20:25:28Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Some features are coded in a mix of Ruby and C (e.g. ractor.rb).</p>
<p>External gems don't have access to this. The C-API to deal with keyword parameters is also very verbose the parsing and the engine does not know it.</p>
<p>Moreover, some optimization PRs are simply rewriting C-code into Ruby using pseudo C code.</p>
<p>I understand the intentions are great, but changes like <a href="https://github.com/ruby/ruby/pull/4018/files" class="external">https://github.com/ruby/ruby/pull/4018/files</a> seem a symptom that something needs to be improved with the C api.</p>
<pre><code class="diff syntaxhl" data-language="diff"><span class="gd">-static VALUE
- flo_zero_p(VALUE num)
- {
- return flo_iszero(num) ? Qtrue : Qfalse;
- }
</span># in different file:
<span class="gi">+ def zero?
+ Primitive.attr! 'inline'
+ Primitive.cexpr! 'flo_iszero(self) ? Qtrue : Qfalse'
+ end
</span></code></pre>
<p>It seems to me that this is a way to circumvent a deeper issue. Is this the right direction?</p>
<p>Is there a plan for an API that would:</p>
<ol>
<li>be accessible to C extensions</li>
<li>can't be re-written any faster in pseuso-C in Ruby</li>
<li>has an easy way to define keyword parameters?</li>
</ol>
<p>I realize that RBS may give perfect signatures, but ideally <code>parameters</code> would be more informative for C-functions too.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Ractor</span><span class="p">.</span><span class="nf">method</span><span class="p">(</span><span class="ss">:yield</span><span class="p">).</span><span class="nf">parameters</span>
<span class="c1"># => [[:req, :obj], [:key, :move]] # good!</span>
<span class="no">Fiber</span><span class="p">.</span><span class="nf">method</span><span class="p">(</span><span class="ss">:initialize</span><span class="p">).</span><span class="nf">parameters</span>
<span class="c1"># => [[:rest]] # not good, should be [[:key, :blocking]]</span>
</code></pre> Ruby master - Feature #17418 (Closed): Add `Ractor.main?` and `Ractor.main`https://bugs.ruby-lang.org/issues/174182020-12-21T16:25:20Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Since main Ractor is special, it seems useful to have an easy way to check if the current ractor is the main ractor.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Ractor</span><span class="p">.</span><span class="nf">main?</span> <span class="c1"># => true</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">main?</span> <span class="p">}.</span><span class="nf">take</span> <span class="c1"># => false</span>
</code></pre>
<p>As far as I know, a gem could be loaded from a non-main Ractor so there is no reliable way for a gem to know the main Ractor (except than trying to do something that is not allowed)</p>
<p>We might as well add <code>Ractor.main</code> to return the main Ractor (probably less useful though).</p> Ruby master - Feature #17406 (Open): Add `NoMatchingPatternError#depth`https://bugs.ruby-lang.org/issues/174062020-12-18T21:45:35Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Could we have <code>NoMatchingPatternError#depth</code>, returning the number of <code>case...in...end</code> an exception has traversed?</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">show_depth</span>
<span class="k">yield</span>
<span class="k">rescue</span> <span class="no">NoMatchingPatternError</span> <span class="o">=></span> <span class="n">e</span>
<span class="nb">puts</span> <span class="s2">"Depth: </span><span class="si">#{</span><span class="n">e</span><span class="p">.</span><span class="nf">depth</span><span class="si">}</span><span class="s2">"</span>
<span class="k">raise</span>
<span class="k">end</span>
<span class="n">show_depth</span> <span class="k">do</span>
<span class="k">case</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">]</span>
<span class="k">in</span> <span class="p">[</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">z</span><span class="p">]</span> <span class="k">then</span>
<span class="n">show_depth</span> <span class="k">do</span>
<span class="n">x</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"># => raises NoMatchingPatternError</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="c1"># Prints "Depth: 0" then "Depth: 1"</span>
</code></pre>
<p>This could help bring pattern match closer to a language construct people can play with.</p>
<p>Example usecase: implement <code>Ractor#receive_if</code> as in <a href="https://bugs.ruby-lang.org/issues/17378#note-6" class="external">https://bugs.ruby-lang.org/issues/17378#note-6</a></p> Ruby master - Misc #17367 (Closed): CI: Env variable for Ractor compatibility tests?https://bugs.ruby-lang.org/issues/173672020-12-05T07:35:56Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>It will become important to test that some features are Ractor compatible.</p>
<p>For some builtin libs for example: that a frozen <code>Matrix</code>/<code>OpenStruct</code> is <code>Ractor.shareable?</code>, or that <code>Integer#prime?</code> works at all.</p>
<p>Could we have an official way to add <a href="https://github.com/ruby/ruby/commit/bc23216e5a4204b8e626704c7277e9edc1708189" class="external">these kinds of tests</a> to the codebase please?</p> Ruby master - Feature #17365 (Closed): Can not respond (well) to a Ractor https://bugs.ruby-lang.org/issues/173652020-12-04T05:05:31Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Summary: currently there is no good way to return a response to a Ractor message.</p>
<p>Sorry, this is long.<br>
Points 1 to 3 look at possible current solutions and why they aren't great.<br>
Point 4 discusses how Elixir/Erlang's builtin filtering allows responses.<br>
Last point proposes one of the many APIs that would allow responses.</p>
<p>Details:</p>
<p>If I want to program a "server" using Ractor, there has to be some way to receive the data from it.<br>
To simplify, say I want a global <code>Config</code> that can be used to set/retrieve some global config parameters.<br>
To set a parameter, I can use <code>server.send [:set, :key, 'value']</code>.<br>
But what about retrieving? There is no good way to achieve that with the current API.</p>
<ol>
<li>"pull" API</li>
</ol>
<p>It is not safe, as two clients could send a <code>:set</code> before the server answers, and the clients could resolve their <code>server.take</code> in the reverse order.</p>
<p>Another issue is that <code>Ractor.yield</code> is blocking, so the unexpected death of the client could mean the server hangs, and subsequent requests/responses are desynchronized and thus wrong.</p>
<p>My impression is that the "pull" API is best only used for monitoring of Ractors, rescuing exceptions, etc., or otherwise reserved for Ractors that are not shared, is this correct?</p>
<ol start="2">
<li>"push" API</li>
</ol>
<p>It seems much more appropriate to design a server such that one sends the client ractor with the push API. E.g. the client calls <code>server.send [:retrieve, :key, Ractor.current]</code>; the server can use the last element <code>cient_ractor</code> to respond with <code>client_ractor.send 'value'</code> that is non-blocking.</p>
<p>The client can then call <code>Ractor.receive</code>, immediately or later, to get the answer.</p>
<p>This is perfect, <em>except</em> that the client can not use <code>Ractor.receive</code> for any other purpose. It can not act itself a server, or if it calls multiple servers then it must do so synchroneously. Otherwise it might <code>receive</code> a request for something other than the response it was waiting for.</p>
<ol start="3">
<li>create Ractor + "push" + "pull"</li>
</ol>
<p>The only way I can think of currently is to create a temporary private Ractor (both to be able to use the "pull" and the "push" API):</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="c1"># on the client:</span>
<span class="n">response</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">server</span><span class="p">,</span> <span class="o">*</span><span class="n">etc</span><span class="p">)</span> <span class="p">{</span> <span class="o">|</span><span class="n">server</span><span class="p">,</span> <span class="o">*</span><span class="n">etc</span><span class="o">|</span>
<span class="n">server</span><span class="p">.</span><span class="nf">send</span> <span class="p">[</span><span class="ss">:retrieve</span><span class="p">,</span> <span class="ss">:key</span><span class="p">,</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">current</span><span class="p">].</span><span class="nf">freeze</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">yield</span><span class="p">(</span><span class="no">Ractor</span><span class="p">.</span><span class="nf">receive</span><span class="p">,</span> <span class="ss">move: </span><span class="kp">true</span><span class="p">)</span>
<span class="p">}.</span><span class="nf">take</span>
<span class="c1"># on the server</span>
<span class="k">case</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">receive</span>
<span class="k">in</span> <span class="p">[</span><span class="ss">:retrieve</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="n">client_ractor</span><span class="p">]</span>
<span class="n">client_ractor</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="s1">'response'</span><span class="p">)</span>
<span class="c1"># ...</span>
<span class="k">end</span>
</code></pre>
<p>I fear this would be quite inefficient (one Ractor per request, extra <code>move</code> of data) and seems very verbose.</p>
<ol start="4">
<li>Filtered <code>receive</code>
</li>
</ol>
<p>If I look at Elixir/Erlang, this is not an issue because the equivalent of <code>Ractor.receive</code> has builtin pattern matching.</p>
<p>The key is that unmatched messages are <a href="https://www.erlang-solutions.com/blog/receiving-messages-in-elixir-or-a-few-things-you-need-to-know-in-order-to-avoid-performance-issues.html#receiving-messages-with-%E2%80%9Ca-priority%E2%80%9D" class="external">queued for later retrieval</a>. This way there can be different <code>Ractor.receive</code> used in different ways in the same Ractor and they will not interact (assuming they use different patterns).</p>
<p>For a general server ("gen_server"), a unique tag is created for each request, that is <a href="https://stackoverflow.com/questions/56741322/gen-serverreply-2-format-of-message-sent-to-client" class="external">sent with the request and with the response</a></p>
<p>The same pattern is possible to implement with Ruby but this can only work if as long as all the <code>Ractor.receive</code> use this implementation in a given Ractor, it has to be thread-safe, etc.</p>
<p>Issue is that it may not be possible to have the same protocol and access to the same <code>receive</code> method, in particular if some of the functionality is provided in a gem.</p>
<ol start="5">
<li>In conclusion...</li>
</ol>
<p>The API of <code>Ractor</code> is currently lacking a good way to handle responses.</p>
<p>It needs to allow filtering/subdivision of the inbox in some way.</p>
<p>One API could be to add a <code>tag: nil</code> parameter to <code>Ractor#send</code> and <code>Ractor.receive</code> that would use that value to match.</p>
<p>A server could decide to use the default <code>nil</code> tag for it's main API, and ask its clients to specify a tag for a response:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">my_tag</span> <span class="o">=</span> <span class="ss">:some_return_tag</span>
<span class="n">server</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="ss">:retrieve</span><span class="p">,</span> <span class="ss">:key</span><span class="p">,</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">current</span><span class="p">,</span> <span class="n">my_tag</span><span class="p">)</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">receive</span> <span class="ss">tag: </span><span class="n">my_tag</span>
<span class="c1"># on the server</span>
<span class="k">case</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">receive</span>
<span class="k">in</span> <span class="p">[</span><span class="ss">:retrieve</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="n">client_ractor</span><span class="p">,</span> <span class="n">client_tag</span><span class="p">]</span>
<span class="n">client_ractor</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="s1">'response'</span><span class="p">,</span> <span class="ss">tag: </span><span class="n">client_tag</span><span class="p">)</span>
<span class="c1"># ...</span>
<span class="k">end</span>
</code></pre>
<p>Tags would have to be Ractor-shareable objects and they could be compared by identity.</p>
<p>Note that messages sent with a non-nil tag (e.g. <code>send 'value' tag: 42</code>) would not be matched by <code>Ractor.receive</code>.<br>
Maybe we should allow for a special <code>tag: :*</code> to match any tag?</p>
<p>There are other solutions possible; a request ID could be returned by <code>Ractor#send</code>, or there could be an API to create object for returns (like a "Self-addressed stamped envelope"), etc.</p>
<p>The basic filtering API I'm proposing has the advantage of being reasonable easy to implement efficiently and still allowing other patterns (for example handling messages by priority, assuming there can be a 0 timeout, see <a class="issue tracker-2 status-2 priority-4 priority-default" title="Feature: Timeouts (Assigned)" href="https://bugs.ruby-lang.org/issues/17363">#17363</a>), but I'll be happy as long as we can offer efficient and reliable builtin ways to respond to Ractor messages.</p> Ruby master - Misc #17329 (Closed): Doc for pattern match?https://bugs.ruby-lang.org/issues/173292020-11-17T01:59:34Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Is there an official doc for pattern matching?</p>
<p>I note that <code>case</code> in <a href="https://ruby-doc.org/core-2.7.2/doc/syntax/control_expressions_rdoc.html" class="external">https://ruby-doc.org/core-2.7.2/doc/syntax/control_expressions_rdoc.html</a> does not mention it, and <code>in</code> does not appear.</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 - Feature #17285 (Open): Less strict `Ractor.select`https://bugs.ruby-lang.org/issues/172852020-10-26T02:49:44Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Summary: could we have a way for <code>Ractor.select</code> to skip ractors with closed queues and raise only if no ractor with an open queue remains?</p>
<p>Detail:</p>
<p>I <a href="https://github.com/marcandre/backports/pull/153" class="external">backported <code>Ractor</code> for earlier Ruby versions</a>, as I'd like to use it in some gems that would work great in 3.0 and work ok in older Rubies without rewriting. That was a lot of fun :-)</p>
<p>One surprise for me was that <code>Ractor.select</code> enforces that no given ractor is terminated(*).</p>
<p>This means that one must remove terminated ractors from a pool of ractors before calling <code>select</code> again:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">pool</span> <span class="o">=</span> <span class="mi">20</span><span class="p">.</span><span class="nf">times</span><span class="p">.</span><span class="nf">map</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="n">do_processing</span> <span class="p">}</span> <span class="p">}</span>
<span class="mi">20</span><span class="p">.</span><span class="nf">times</span> <span class="k">do</span>
<span class="n">ractor</span><span class="p">,</span> <span class="n">result</span> <span class="o">=</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">select</span><span class="p">(</span><span class="o">*</span><span class="n">pool</span><span class="p">)</span>
<span class="n">handle</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
<span class="n">pool</span><span class="p">.</span><span class="nf">delete</span><span class="p">(</span><span class="n">ractor</span><span class="p">)</span> <span class="c1"># necessary!</span>
<span class="k">end</span>
</code></pre>
<ol start="0">
<li>
<p>This can be tedious, but I know I'm very lazy</p>
</li>
<li>
<p>It is not convenient to share a pool between different ractors. Try writing code that starts 5 ractors that would consume the results from <code>pool</code> above.</p>
</li>
<li>
<p>It might require special synchronization if the ractors may yield a variable number of values:</p>
</li>
</ol>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">do_processing</span>
<span class="nb">rand</span><span class="p">(</span><span class="mi">10</span><span class="p">).</span><span class="nf">times</span> <span class="k">do</span> <span class="p">{</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">yield</span> <span class="ss">:a_result</span>
<span class="p">}</span>
<span class="ss">:finish</span>
<span class="k">end</span>
<span class="n">pool</span> <span class="o">=</span> <span class="mi">20</span><span class="p">.</span><span class="nf">times</span><span class="p">.</span><span class="nf">map</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="n">do_processing</span> <span class="p">}</span> <span class="p">}</span>
<span class="k">until</span> <span class="n">pool</span><span class="p">.</span><span class="nf">empty?</span> <span class="k">do</span>
<span class="n">ractor</span><span class="p">,</span> <span class="n">result</span> <span class="o">=</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">select</span><span class="p">(</span><span class="o">*</span><span class="n">pool</span><span class="p">)</span>
<span class="k">if</span> <span class="n">result</span> <span class="o">==</span> <span class="ss">:finish</span>
<span class="n">pool</span><span class="p">.</span><span class="nf">delete</span><span class="p">(</span><span class="n">ractor</span><span class="p">)</span>
<span class="k">else</span>
<span class="n">do_something_with</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>I would like to propose that it would be allowed (by default or at least via keyword parameter) to call <code>select</code> on terminated ractors, as long as there is at least one remaining open one.</p>
<p>This would make it very to resolve 1 and 2 above. Here's an example combine them both together:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">do_processing</span>
<span class="nb">rand</span><span class="p">(</span><span class="mi">10</span><span class="p">).</span><span class="nf">times</span> <span class="k">do</span> <span class="p">{</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">yield</span> <span class="ss">:a_result</span>
<span class="p">}</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">current</span><span class="p">.</span><span class="nf">close</span> <span class="c1"># avoid yielding a value at the end</span>
<span class="k">end</span>
<span class="n">pool</span> <span class="o">=</span> <span class="mi">20</span><span class="p">.</span><span class="nf">times</span><span class="p">.</span><span class="nf">map</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="n">do_processing</span> <span class="p">}</span> <span class="p">}.</span><span class="nf">freeze</span>
<span class="mi">5</span><span class="p">.</span><span class="nf">times</span> <span class="k">do</span> <span class="c1"># divide processing into 5 ractors</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">pool</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">pool</span><span class="o">|</span>
<span class="kp">loop</span> <span class="k">do</span>
<span class="n">_ractor</span><span class="p">,</span> <span class="n">result</span> <span class="o">=</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">select</span><span class="p">(</span><span class="o">*</span><span class="n">pool</span><span class="p">)</span> <span class="c1"># with my proposed lax select</span>
<span class="n">do_something_with</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>The <code>loop</code> above terminates when <code>Ractor.select</code> raises an error once the whole <code>pool</code> is terminated.</p>
<p>I'm new to actors but my intuition currently is that I will never want to take care of a pool of Ractors myself and would always prefer if <code>Ractor.select</code> did it for me. Are there use-cases where <code>Ractor.select</code> raising an error if it encounters a closed queue is helpful?</p>
<p>Notes:</p>
<ul>
<li>(*) <code>Ractor.select</code> doesn't really enforce ractors to be opened of course, it will work if the ractors are consumed in the right order, like in this example by chance:</li>
</ul>
<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="nf">map</span> <span class="k">do</span>
<span class="n">r</span> <span class="o">=</span> <span class="mi">2</span><span class="p">.</span><span class="nf">times</span><span class="p">.</span><span class="nf">map</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.05</span><span class="p">);</span> <span class="ss">:ok</span> <span class="p">}</span> <span class="p">}</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">select</span><span class="p">(</span><span class="o">*</span><span class="n">r</span><span class="p">)</span> <span class="c1"># Get first available result</span>
<span class="c1"># Don't remove the ractor from `r`</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">select</span><span class="p">(</span><span class="o">*</span><span class="n">r</span><span class="p">).</span><span class="nf">last</span> <span class="k">rescue</span> <span class="ss">:error</span> <span class="c1"># Get second result</span>
<span class="k">end</span>
<span class="c1"># => [:ok, :error, :error, :error, :error, :error, :error, :ok, :ok, :ok]</span>
</code></pre>
<ul>
<li>I think <code>Ractor.select(*pool, yield_value: 42)</code> would raise only if the current outgoing queue is closed, even if the whole pool was terminated</li>
<li>Similarly <code>Ractor.select(*pool, Ractor.current)</code> would raise only if the current incomming queue is also closed.</li>
</ul> Ruby master - Feature #17265 (Feedback): Add `Bool` modulehttps://bugs.ruby-lang.org/issues/172652020-10-19T00:11:59Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>1-line Summary: <code>rbs</code> would benefit from the existence of common ancestor <code>Bool</code> for <code>TrueClass</code> and <code>FalseClass</code>.</p>
<p>Detail:<br>
Matz: I am aware you rejected a similar request, but could we revisit this in light of RBS?</p>
<p>One use case was for an easy way to check for <code>true</code> or <code>false</code> values, instead of simply for truthiness (e.g. for data transfer, strict argument checking, testing, etc.)</p>
<p>I believe there's a new use case: <code>RBS</code></p>
<p>In <code>RBS</code>, the most used types like <code>String</code> and <code>Integer</code> have types for "string-like" and "integer-like" objects: <code>string</code> and <code>integer</code> (all lowercase).</p>
<p>For example the signature for <code>Integer#>></code> is:</p>
<pre><code>def >>: (int) -> Integer
</code></pre>
<p>It accepts an <code>Integer</code> <em>or an object responding to <code>to_int</code></em> (summarized by <code>int</code>) and returns an <code>Integer</code> (and never another class of object responding to <code>to_int</code> or not).</p>
<p>There is a similar idea with boolean values, where a method may accept any object and will use it's truthiness, while returning <code>true | false</code>. For example one of the interface for <code>Enumerable#all?</code> should look like:</p>
<pre><code>def all?: () { (Elem) -> bool } -> true | false
</code></pre>
<p>The user supplied block can return any value, and its truthiness (anything else than <code>nil</code> or <code>false</code>) will be used to determine the result of <code>all?</code>. That result will be <code>true | false</code>, and no other value.</p>
<p>If RBS is to be popular, there will be <em>many</em> signatures for such predicates (in builtin Ruby, stdlib, any gems, applications, etc.). I feel the best option would be <code>Bool</code>, if this would be reflected in Ruby itself.</p>
<p>Proposal: a new global module called <code>Bool</code>, without any method of constant, included in <code>TrueClass</code> and <code>FalseClass</code>.</p>
<p>Following reasons for rejection were given at the time:</p>
<blockquote>
<p>many gems and libraries had already introduced Boolean class. I don't want to break them.</p>
</blockquote>
<p>I looked and found the <a href="https://rubygems.org/gems/bool" class="external"><code>bool</code> gem</a> that defines a <code>Bool</code> module. My proposal is compatible. In any case, this gem looks abandoned, the author Aslak Hellesøy doesn't have the code on github, the gem has had 7000 downloads in the past 6 years and <a href="https://rubygems.org/gems/bool/reverse_dependencies" class="external">has no public reverse dependency</a>. It also fails to install on my machine.</p>
<p>I am not aware of incompatibilities.</p>
<blockquote>
<p><code>true</code> and <code>false</code> are the only representative of true-false values. In Ruby. <code>nil</code> and <code>false</code> are falsy values, and everything else is a true value. There's no meaning for having a superclass of <code>TrueClass</code> and <code>FalseClass</code> as <code>Boolean</code>.</p>
</blockquote>
<p>The proposal is exactly to be able to easily write about this duality of <code>Bool</code> as having only <code>true</code> and <code>false</code> as members, and every Ruby object as being implicitly convertible as being truthy or falsy (<code>bool</code> in RBS).</p>
<p>Discussion in RBS:</p>
<ul>
<li><a href="https://github.com/ruby/rbs/issues/133" class="external">https://github.com/ruby/rbs/issues/133</a></li>
</ul>
<p>Previous feature requests for <code>Boolean</code>:</p>
<ul>
<li><a href="https://bugs.ruby-lang.org/issues/14224" class="external">https://bugs.ruby-lang.org/issues/14224</a></li>
<li><a href="https://bugs.ruby-lang.org/issues/12515" class="external">https://bugs.ruby-lang.org/issues/12515</a></li>
</ul> 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 - Feature #16985 (Open): Improve `pp` for `Hash` and `String`https://bugs.ruby-lang.org/issues/169852020-06-25T17:28:06Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Could we improve <code>pp</code> for <code>Hash</code> and <code>String</code>:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">pp</span><span class="p">({</span><span class="ss">hello: </span><span class="s1">'My name is "Marc-André"'</span><span class="p">})</span>
<span class="c1"># =></span>
<span class="p">{</span><span class="ss">hello: </span><span class="s1">'My name is "Marc-André"'</span><span class="p">}</span>
<span class="c1"># instead of</span>
<span class="p">{</span><span class="ss">:hello</span><span class="o">=></span><span class="s2">"My name is </span><span class="se">\"</span><span class="s2">Marc-André</span><span class="se">\"</span><span class="s2">"</span><span class="p">}</span>
</code></pre>
<p>If any key is non-symbol, they would continue to be output as <code><key> => <value></code>. If a string contains single quotes, or characters that need escaping (e.g. <code>"\n"</code>), current format would be used.</p>
<p>I'll gladly provide a PR if this is deemed acceptable.</p>
<p>I would even like this for <code>String#inspect</code> and <code>Hash#inspect</code> but it's not clear if this could lead to much incompatibility (maybe test suites?)</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 - Feature #15330 (Open): autoload_relativehttps://bugs.ruby-lang.org/issues/153302018-11-21T23:43:41Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I'd like to propose a way to autoload a constant using a relative path.</p>
<p>It could look like:</p>
<pre><code>autoload_relative :MyConst, 'models/my_const'
</code></pre>
<p>My proposal raises two questions:</p>
<ol>
<li>what's the future of <code>autoload</code>?</li>
</ol>
<p>I believe that <code>autoload</code> has been there for years, it is used successfully and has no real alternative.</p>
<p>I looked at a sample of 430 top gems (took the 500 top ranked according to Libraries.io, removed those that I failed to process). The number of those gems that appear to use <code>autoload</code> at least once is 94 of those (22%).</p>
<p>The number of lines in the code where <code>autoload</code> is called can be quite big. The top 5 are:<br>
vagrant: 235<br>
yard: 206<br>
ffaker: 155<br>
aws-sdk: 152<br>
rdoc: 92</p>
<p>This is a minimum bound, as some gems might be using loops, my processing would only detect the one place in the code with <code>autoload</code>.</p>
<ol start="2">
<li>are many autoladed paths relative?</li>
</ol>
<p>My preliminary numbers indicate that of the 94 gems using autoload, at least 75 are autoloading some relative files. That's a lower bound, as my algorithm is pretty crude and will only count the simplest cases as being relative. An example of gem my algorithm does not detect is <code>yard</code>, because the author wrote a small method to map the relative paths to global paths (code here: <a href="https://github.com/lsegal/yard/blob/master/lib/yard/autoload.rb#L3" class="external">https://github.com/lsegal/yard/blob/master/lib/yard/autoload.rb#L3</a> )</p>
<p>Of those where my processing detects the relative requires, a vast majority are relative. The average is that 94% of autoloaded files are relative and would benefit from <code>require_relative</code></p>
<p>In summary: I am convinced that <code>autoload</code> should remain in Ruby indefinitely. <code>autoload_relative</code> would actually be more useful than <code>autoload</code>. Even if the future of <code>autoload</code> remains uncertain, I would recommend adding <code>autoload_relative</code>; if it is ever decided to actually remove <code>autoload</code>, removing <code>autoload_relative</code> would not really add to the (huge) burden of gem maintainers.</p> Ruby master - Feature #15277 (Open): at_exechttps://bugs.ruby-lang.org/issues/152772018-11-02T19:23:47Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>There's currently no easy way to have code executed before a subsequent call to <code>exec</code>. One has to monkey-patch the builtin method.</p>
<p>I'd like to propose a new method <code>at_exec</code> that would be very similar to <code>at_exit</code>, except that the callbacks are triggered before the current process is replaced by the external command.</p>
<pre><code># This would output "Hello", "Bye", and "Foo"
at_exec { puts "Bye!" }
puts "Hello"
exec "echo Foo"
</code></pre>
<p>Use case: we roll our own in <code>DeepCover</code>. Some test suites will call <code>exec</code>, and we need to store our counters before that happens.</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 #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 - Feature #12813 (Closed): Calling chunk_while, slice_after, slice_before, slice_when...https://bugs.ruby-lang.org/issues/128132016-10-06T04:43:55Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Currently, <code>chunk_while</code>, <code>slice_after</code>, <code>slice_before</code>, <code>slice_when</code> all require a block.</p>
<p>If one needs the index within the block, there is no good way to do this; <code>enum.each_with_index.chunk_while</code> would have indices in the results, so <code>enum.enum_for(:chunk_while).with_index</code> is the best solution.</p>
<p>I feel that we should return <code>enum_for(:chunk_while)</code>. This is strictly more useful than raising as we currently do.</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 - Feature #9347 (Open): Accept non callable argument to detecthttps://bugs.ruby-lang.org/issues/93472014-01-03T07:37:33Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Currently, the only argument that <code>Enumerable#detect</code> accepts is a callable object.</p>
<p>Shouldn't we accept non callable objects too?</p>
<pre><code>[42].detect(:not_found){} # => NoMethodError: undefined method `call' for :not_found:Symbol
# would return :not_found instead.
</code></pre>
<p>I'd suggest that if the given argument does not <code>respond_to? :call</code>, then it would be returned as is instead of raising an error as currently.<br>
Wouldn't this be more flexible and possibly more performant?</p>
<p>Inspired by <a href="http://stackoverflow.com/questions/20883414/why-does-enumerabledetect-need-a-proc-lambda" class="external">http://stackoverflow.com/questions/20883414/why-does-enumerabledetect-need-a-proc-lambda</a></p> Backport21 - Backport #9270 (Closed): Array#to_h should not ignore badly formed elementshttps://bugs.ruby-lang.org/issues/92702013-12-21T02:59:27Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>The upcoming Array#to_h feature currently ignores elements that are not 2-elements arrays. Array#to_h could instead raise an error on those elements. I argued otherwise before, but maybe that would be safer.</p>
<p>One reason I think I was wrong is that current form could encourage code like:</p>
<p>enum.map{|x| [x.foo, x.bar] if x.baz? }.to_h</p>
<p>using the fact that any <code>nil</code> will be ignored. I'm not sure that it's a good idea.</p>
<p>It would probably be safer to raise an Exception for elements that are not a key-value pair. It also satisfies fail-early principle.</p>
<p><a class="user active user-mention" href="https://bugs.ruby-lang.org/users/2963">@sawa (Tsuyoshi Sawada)</a> agrees with this.<br>
<a class="user active user-mention" href="https://bugs.ruby-lang.org/users/13">@matz (Yukihiro Matsumoto)</a> agrees with the change.</p>
<p>Since this feature has not already been released in an official version, changing this behavior now would not cause any incompatibility and there should be no risk of regression. Changing this feature after the official 2.1 release would be more problematic as it could cause incompatibilities.</p>
<p>Yui, could you please confirm that there is no problem on your end for me to commit the following patch: <a href="https://github.com/marcandre/ruby/compare/to_h_raise" class="external">https://github.com/marcandre/ruby/compare/to_h_raise</a></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 #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> Backport200 - Backport #7935 (Closed): Array#sample with random generatorhttps://bugs.ruby-lang.org/issues/79352013-02-24T13:00:13Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>The Random generator method's rand is called with the wrong limit.</p>
<p>Kernel::rand(n) returns integer between 0 and n-1, but generator is called with (n-1).</p>
<p>For example:</p>
<p>require 'delegate'<br>
[1, 2].sample(1, random: Random.new) # => [1], or [2]<br>
[1, 2].sample(1, random: SimpleDelegator.new(Random.new)) # => [1], never [2]</p>
<p>test_random_ulong_limited</p> Backport200 - Backport #7922 (Closed): Keyword arguments bug with unnamed resthttps://bugs.ruby-lang.org/issues/79222013-02-24T00:44:47Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>We have:</p>
<pre><code>def foo(**ignore_all_options)
end
foo(bar: 42) # => nil, OK
method(:foo).parameters # => [[:keyrest, :ignore_all_options]], OK
</code></pre>
<p>But:</p>
<pre><code>def foo(**)
end
foo(bar: 42) # => ArgumentError: unknown keyword: bar, expected nil
method(:foo).parameters # => [], expected [[:keyrest]]
</code></pre> 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 #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 - Feature #7444 (Open): Array#product_sethttps://bugs.ruby-lang.org/issues/74442012-11-27T14:44:28Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>I'd like to propose <code>Array#product_set</code> to return the product set of arrays (aka cartesian product)</p>
<pre><code>deck = [1..13, %i(spades hearts diamond clubs)].product_set
# => <#Enumerator ...>
deck.first(2) # => [[1, :spades], [2, :spades]]
</code></pre>
<p><code>product_set</code> would return an enumerator if no block is given. It should raise an error if an element of the array is not an Enumerable, like Array#transpose or #zip do.</p>
<p>Although <code>Array.product</code> would be acceptable too, I feel that an instance method of array is best in the case, in the same way that <code>transpose</code> is an instance method and not a class method.</p>
<p>The name "product_set" is a correct mathematical term. Although the synonym "cartesian_product" would also be acceptable, I propose "product_set" because it is shorter and cute too. I feel it is even clearer than <code>product</code>; the first time I head of <code>product</code> I was convinced that <code>[2,3,7].product # => 42</code>.</p>
<p>Addressing objections raised in <a class="issue tracker-2 status-6 priority-4 priority-default closed" title="Feature: Array::zip (Rejected)" href="https://bugs.ruby-lang.org/issues/6499">#6499</a>:</p>
<ol>
<li>This is not for the sake of symmetry, but because often we have an array of the arrays we want a product of.</li>
</ol>
<p>It is cumbersome to write <code>arrays.first.product(*arrays[1..-1])</code> or similar and it hides what is going on.</p>
<p>Writing <code>arrays.product_set</code> is much nicer.</p>
<ol start="2">
<li>
<p>The goal is not mainly to get a lazy version, but more to make the API better. The fact that it returns an Enumerator if no block is given is just a bonus :-)</p>
</li>
<li>
<p>[].product_set.to_a # => [[]]</p>
</li>
</ol>
<p>This can be seen from a cardinality argument, or for example because <code>array.repeated_permutation(n) == Array.new(n, array).product_set.to_a</code> and <code>array.repeated_permutation(0) == [[]]</code>.</p> Ruby master - Feature #7292 (Closed): Enumerable#to_hhttps://bugs.ruby-lang.org/issues/72922012-11-07T02:53:45Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Now that #to_h is the official method for explicit conversion to Hash, we should also add</p>
<pre><code>Enumerable#to_h: Returns a hash for the yielded key-value pairs.
[[:name, 'Joe Smith'], [:age, 42]].to_h # => {name: 'Joe Smith', age: 42}
</code></pre>
<p>With the Ruby tradition of succint documentation I suggest the documentation talk about key-value pairs and there is no need to be explicit about the uninteresting cases like:</p>
<pre><code>(1..3).to_h # => {1 => nil, 2 => nil, 3 => nil}
[[1, 2], [1, 3]].to_h # => {1 => 3}
[[1, 2], []].to_h # => {1 => 2, nil => nil}
</code></pre>
<p>I see some reactions of people reading about the upcoming 2.0 release like this one:<br>
<a href="http://globaldev.co.uk/2012/11/ruby-2-0-0-preview-features/#dsq-comment-body-700242476" class="external">http://globaldev.co.uk/2012/11/ruby-2-0-0-preview-features/#dsq-comment-body-700242476</a></p> Ruby master - Feature #6693 (Closed): Don't warn for unused variables starting with _https://bugs.ruby-lang.org/issues/66932012-07-04T13:01:12Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Currently, variables which are set but not used will generate a warning (ruby -w), except if they have the special name "_".</p>
<p>So best practice is to use "_" for all unused variables. This does not encourage readable code.</p>
<pre><code># Currently must read:
_, _, _, suffix = parse_name
# could read:
_first, _middle, _last, suffix = parse_name
</code></pre>
<p>We should not warn for unused variables starting with a "_".</p>
<p>This would create an option (but no obligation) to use more descriptive names than "_" without generating warnings.</p> Ruby master - Feature #6636 (Closed): Enumerable#sizehttps://bugs.ruby-lang.org/issues/66362012-06-24T02:49:38Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Now that it has been made clear that <code>Enumerable#count</code> never calls <code>#size</code> and that we have <code>Enumerable#lazy</code>, let me propose again an API for a lazy way to get the size of an Enumerable: <code>Enumerable#size</code>.</p>
<ul>
<li>call-seq:</li>
<li>enum.size # => nil, Integer or Float::INFINITY</li>
<li>
<li>Returns the number of elements that will be yielded, without going through</li>
<li>the iteration (i.e. lazy), or +nil+ if it can't be calculated lazily.</li>
<li>
<li>perm = (1..100).to_a.permutation(4)</li>
<li>perm.size # => 94109400</li>
<li>perm.each_cons(2).size # => 94109399</li>
<li>loop.size # => Float::INFINITY</li>
<li>[42].drop_while.size # => nil</li>
</ul>
<p>About 66 core methods returning enumerators would have a lazy <code>size</code>, like <code>each_slice</code>, <code>permutation</code> or <code>lazy.take</code>.</p>
<p>A few would have <code>size</code> return <code>nil</code>:<br>
Array#{r}index, {take|drop}_while<br>
Enumerable#find{_index}, {take|drop}_while<br>
IO: all methods</p>
<p>Sized enumerators can also be created naturally by providing a block to <code>to_enum</code>/<code>enum_for</code> or a lambda to <code>Enumerator.new</code>.</p>
<p>Example for <code>to_enum</code>:</p>
<pre><code>class Integer
def composition
return to_enum(:composition){ 1 << (self - 1) } unless block_given?
yield [] if zero?
downto(1) do |i|
(self - i).composition do |comp|
yield [i, *comp]
end
end
end
end
4.composition.to_a
# => [[4], [3, 1], [2, 2], [2, 1, 1], [1, 3], [1, 2, 1], [1, 1, 2], [1, 1, 1, 1]]
42.composition.size # => 2199023255552
</code></pre>
<p>Example for <code>Enumerator.new</code>:</p>
<pre><code>def lazy_product(*enums)
sizer = ->{
enums.inject(1) do |product, e|
break if (size = e.size).nil?
product * size
end
}
Enumerator.new(sizer) do |yielder|
# ... generate combinations
end
end
lazy_product(1..4, (1..3).each_cons(2)).size # => 8
lazy_product(1..4, (1..3).cycle).size # => Float::INFINITY
</code></pre> Ruby master - Feature #6240 (Closed): Enumerable#drop with negative argumenthttps://bugs.ruby-lang.org/issues/62402012-04-01T05:57:41Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Currently, Enumerable#drop works only for non-negative arguments.</p>
<p>It could be extended so that negative arguments means dropping from the end:</p>
<pre><code>[:hello, :world].drop(-1) # => [:hello]
</code></pre>
<p>This could especially be interesting for <code>Lazy#drop</code>, which would keep a circular buffer of elements before yielding them.</p>
<pre><code>(1..6).lazy.drop(-3).each{|x| puts x} # -> prints 1, 2 and 3
</code></pre>
<p>Thoughts?</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> Backport193 - Backport #6044 (Closed): Float#% bug in cornercaseshttps://bugs.ruby-lang.org/issues/60442012-02-18T09:26:57Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>On my platform, current behavior is:</p>
<p>4.0 % Float::INFINITY # => NaN<br>
4.0.send :%, Float::INFINITY # => 4.0</p>
<p>-0.0 % 42 # => 0.0<br>
-0.0.send(:%, 42) # => -0.0</p>
<p>On some platforms, these might return NaN and 0.0 in all cases.</p>
<p>My proposed behavior is to return 4.0 and -0.0 on all cases and on all platforms.</p>
<p>I'm tempted to assume it is clear that this is bug and that my proposed behavior is the right solution, but let me use my guidelines:</p>
<p>Proposed behavior passes my "strict superiority test" as it is clearly more consistent:</p>
<ul>
<li>consistent for different calling methods</li>
<li>consistent accross platforms</li>
<li>consistent with 4 % Float::INFINITY</li>
<li>consistent with the IEEE definition of fmod (see <a href="http://pubs.opengroup.org/onlinepubs/007904975/functions/fmod.html" class="external">http://pubs.opengroup.org/onlinepubs/007904975/functions/fmod.html</a> )</li>
</ul>
<p>It is also more intuitive and useful, since:</p>
<p>any_small_number % any_big_number == any_small_number</p>
<p>Current behavior passes the "clear defect test" as it is platform dependent (when it can reasonable be platfom independent). I'll add to the list of "clear defect" criteria the fact that calling an operator directly doesn't yield the same result as using <code>#send</code>.</p>
<p>The proposed solution fails my "straightforward" test as the proposed behavior contradicts part of the documentation which states "x.modulo(y) means x-y*(x/y).floor".</p>
<p>Any objection for me to commit this?</p>
<a name="Thanks"></a>
<h2 >Thanks<a href="#Thanks" class="wiki-anchor">¶</a></h2>
<p>Marc-André</p> 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 #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> Backport193 - Backport #5272 (Closed): Float#round doesn't round big valueshttps://bugs.ruby-lang.org/issues/52722011-09-05T05:08:21Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>For large enough values (outside of Fixnum range), Float#round does not round at all but simply truncates:</p>
<p>2.999999999999999e20.round(-20) # => 200000000000000000000</p>
<p>Fixed in trunk, but would be nice to backport for Ruby 1.9.3.</p> Backport193 - Backport #5271 (Closed): Integer#round should never return a Floathttps://bugs.ruby-lang.org/issues/52712011-09-05T04:24:45Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Integer#round sometimes returns... a float!</p>
<pre><code>42.round(-1e9) # => 0.0
</code></pre>
<p>There's a check for out of range arguments, but it's not really needed and is machine dependent.</p>
<p>The following patch fixes the issue by optimizing for most cases and double checking for the rare extremely unlikely case where 10**ndigits does not fit in a bignum but <code>num</code> does and has almost <code>ndigits</code> digits.</p>
<p>Committed to trunk but would be nice to backport for Ruby 1.9.3.</p>
<p>diff --git a/numeric.c b/numeric.c<br>
index 201dfab..a767fa5 100644<br>
--- a/numeric.c<br>
+++ b/numeric.c<br>
@@ -3320,6 +3320,7 @@ int_round(int argc, VALUE* argv, VALUE num)<br>
{<br>
VALUE n, f, h, r;<br>
int ndigits;</p>
<ul>
<li>
<p>long bytes;<br>
ID op;</p>
<p>if (argc == 0) return num;<br>
@@ -3331,11 +3332,15 @@ int_round(int argc, VALUE* argv, VALUE num)<br>
if (ndigits == 0) {<br>
return num;<br>
}</p>
</li>
</ul>
<ul>
<li>ndigits = -ndigits;</li>
<li>if (ndigits < 0) {</li>
<li>
<pre><code> rb_raise(rb_eArgError, "ndigits out of range");
</code></pre>
</li>
</ul>
<ul>
<li>
<li>/* If 10**N / 2 > num, then return 0 */</li>
<li>/* We have log_256(10) > 0.415241 and log_256(1/2) = -0.125, so */</li>
<li>bytes = FIXNUM_P(num) ? sizeof(long) : rb_funcall(num, rb_intern("size"), 0);</li>
<li>if (-0.415241 * ndigits - 0.125 > bytes ) {</li>
<li>
<pre><code> return INT2FIX(0);
</code></pre>
}</li>
</ul>
<ul>
<li>f = int_pow(10, ndigits);</li>
</ul>
<ul>
<li>
<li>f = int_pow(10, -ndigits);<br>
if (FIXNUM_P(num) && FIXNUM_P(f)) {<br>
SIGNED_VALUE x = FIX2LONG(num), y = FIX2LONG(f);<br>
int neg = x < 0;<br>
@@ -3344,6 +3349,10 @@ int_round(int argc, VALUE* argv, VALUE num)<br>
if (neg) x = -x;<br>
return LONG2NUM(x);<br>
}</li>
<li>if (TYPE(f) == T_FLOAT) {</li>
<li>
<pre><code> /* then int_pow overflow */
</code></pre>
</li>
<li>
<pre><code> return INT2FIX(0);
</code></pre>
</li>
<li>}<br>
h = rb_funcall(f, '/', 1, INT2FIX(2));<br>
r = rb_funcall(num, '%', 1, f);<br>
n = rb_funcall(num, '-', 1, r);</li>
</ul> 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 - Feature #4938 (Closed): Add Random.bytes [patch]https://bugs.ruby-lang.org/issues/49382011-06-28T00:58:10Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>It could be useful to add a <code>Random.bytes</code> method (equivalent to <code>Random::DEFAULT.bytes</code>), as per the simple patch attached.</p> Ruby master - Feature #3715 (Rejected): Enumerator#size and #size=https://bugs.ruby-lang.org/issues/37152010-08-19T05:02:27Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
It would be useful to be able to ask an Enumerator for the number of times it will yield, without having to actually iterate it.</p>
<p>For example:</p>
<p>(1..1000).to_a.permutation(4).size # => 994010994000 (instantly)</p>
<p>It would allow nice features like:</p>
<p>class Enumerator<br>
def with_progress<br>
return to_enum :with_progress unless block_given?<br>
out_of = size || "..."<br>
each_with_index do |obj, i|<br>
puts "Progress: #{i} / #{out_of}"<br>
yield obj<br>
end<br>
puts "Done"<br>
end<br>
end</p>
<a name="To-display-the-progress-of-any-iterator-one-can-daisy-chain-with_progress"></a>
<h1 >To display the progress of any iterator, one can daisy-chain with_progress:<a href="#To-display-the-progress-of-any-iterator-one-can-daisy-chain-with_progress" class="wiki-anchor">¶</a></h1>
<p>20.times.with_progress.map do<br>
# do stuff here...<br>
end</p>
<p>This would print out "Progress: 1 / 20", etc..., while doing the stuff.</p>
<p>*** Proposed changes ***</p>
<ul>
<li>Enumerator#size *</li>
</ul>
<p>call-seq:<br>
e.size -> int, Float::INFINITY or nil<br>
e.size {block} -> int</p>
<p>Returns the size of the enumerator.<br>
The form with no block given will do a lazy evaluation of the size without going through the enumeration. If the size can not be determined then +nil+ is returned.<br>
The form with a block will always iterate through the enumerator and return the number of times it yielded.</p>
<p>(1..100).to_a.permutation(4).size # => 94109400<br>
loop.size # => Float::INFINITY</p>
<p>a = [1, 2, 3]<br>
a.keep_if.size # => 3<br>
a # => [1, 2, 3]<br>
a.keep_if.size{false} # => 3<br>
a # => []</p>
<p>[1, 2, 3].drop_while.size # => nil<br>
[1, 2, 3].drop_while.size{|i| i < 3} # => 2</p>
<ul>
<li>Enumerator#size= *</li>
</ul>
<p>call-seq:<br>
e.size = sz</p>
<p>Sets the size of the enumerator. If +sz+ is a Proc or a Method, it will be called each time +size+ is requested, otherwise +sz+ is returned.</p>
<p>first = [1, 2, 3]<br>
second = [4, 5]<br>
enum = Enumerator.new do |y|<br>
first.each{|o| y << o}<br>
second.each{|o| y << o}<br>
end<br>
enum.size # => nil<br>
enum.size = ->(e){first.size + second.size}<br>
enum.size # => 5<br>
first << 42<br>
enum.size # => 6</p>
<ul>
<li>Kerne#to_enum / enum_for *</li>
</ul>
<p>The only other API change is for #to_enum/#enum_for, which can accept a block for size calculation:</p>
<p>class Date<br>
def step(limit, step=1)<br>
unless block_given?<br>
return to_enum(:step, limit, step){|date| (limit - date).div(step) + 1}<br>
end<br>
# ...<br>
end<br>
end</p>
<p>*** Implementation ***</p>
<p>I implemented the support for #size for most builtin enumerator producing methods (63 in all).</p>
<p>It is broken down in about 20 commits: <a href="http://github.com/marcandre/ruby/commits/enum_size" class="external">http://github.com/marcandre/ruby/commits/enum_size</a></p>
<p>It begins with the implementation of Enumerator#size{=}: <a href="http://github.com/marcandre/ruby/commit/a92feb0" class="external">http://github.com/marcandre/ruby/commit/a92feb0</a></p>
<p>A combined patch is available here: <a href="http://gist.github.com/535974" class="external">http://gist.github.com/535974</a></p>
<p>Still missing are Dir#each, Dir.foreach, ObjectSpace.each_object, Range#step, Range#each, String#upto, String#gsub, String#each_line.</p>
<p>The enumerators whose #size returns +nil+ are:<br>
Array#{r}index, {take|drop}_while<br>
Enumerable#find{_index}, {take|drop}_while<br>
IO: all methods</p>
<p>*** Notes ***</p>
<ul>
<li>Returning +nil+ *</li>
</ul>
<p>I feel it is best if IO.each_line.size and similar return +nil+ to avoid side effects.</p>
<p>We could have Array#find_index.size return the size of the array with the understanding that this is the maximum number of times the enumerator will yield. Since a block can always contain a break statement, size could be understood as a maximum anyways, so it can definitely be argued that the definition should be the maximum number of times.</p>
<ul>
<li>Arguments to size proc/lambda *</li>
</ul>
<p>My implementation currently passes the object that the enumerator will call followed with any arguments given when building the enumerator.</p>
<p>If Enumerator had getters (say Enumerator#base, Enumerator#call, Enumerator#args, see feature request <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: Add getters for Enumerator (Closed)" href="https://bugs.ruby-lang.org/issues/3714">#3714</a>), passing the enumerator itself might be a better idea.</p>
<ul>
<li>Does not dispatch through name *</li>
</ul>
<p>It might be worth noting that the size dispatch is decided when creating the enumerator, not afterwards in function of the class & method name:</p>
<p>[1,2,3].permutation(2).size # => 6<br>
[1,2,3].to_enum(:permutation, 2).size # => nil</p>
<ul>
<li>Size setter *</li>
</ul>
<p>Although I personally like the idea that #size= can accept a Proc/Lambda for later call, this has the downside that there is no getter, i.e. no way to get the Proc/Lambda back. I feel this is not an issue, but an alternative would be to have a #size_proc and #size_proc= setters too (like Hash).</p>
<p>I believe this addresses feature request <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>, although maybe in a different fashion. <a href="http://redmine.ruby-lang.org/issues/show/2673" class="external">http://redmine.ruby-lang.org/issues/show/2673</a><br>
=end</p> Ruby master - Feature #3714 (Closed): Add getters for Enumeratorhttps://bugs.ruby-lang.org/issues/37142010-08-19T04:51:48Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Given an enumerator, there is no way to know what receiver, method and arguments it is based upon (although one could use Enumerator#inspect and parse it to get the method).</p>
<p>For sake of completeness and introspection, it could be useful to have access to them.</p>
<p>This patch adds Enumerator#receiver, #method and #arguments: <a href="http://github.com/marcandre/ruby/commit/fd4c17f7fd" class="external">http://github.com/marcandre/ruby/commit/fd4c17f7fd</a></p>
<p>Note that for Enumerator created with a block like Enumerator.new{|y| y << 1 << 2}, then receiver is a Enumerator::Generator, method is :each and arguments is []. This is consistent with inspect.</p>
<p>Thanks.<br>
=end</p> Backport191 - Backport #3506 (Closed): Kernel::URI with optional parserhttps://bugs.ruby-lang.org/issues/35062010-06-30T05:43:40Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Kernel::URI could accept an optional parameter to specify a parser.</p>
<p>It could then be used in a couple of places in the library itself.</p>
<p>Patch follows:</p>
<p>diff --git a/lib/uri/common.rb b/lib/uri/common.rb<br>
index bda6718..f9f0a6a 100644<br>
--- a/lib/uri/common.rb<br>
+++ b/lib/uri/common.rb<br>
@@ -185,14 +185,7 @@ module URI<br>
end</p>
<pre><code> def join(*uris)
</code></pre>
<ul>
<li>
<pre><code> case uris[0]
</code></pre>
</li>
<li>
<pre><code> when Generic
</code></pre>
</li>
<li>
<pre><code> when String
</code></pre>
</li>
<li>
<pre><code> uris[0] = self.parse(uris[0])
</code></pre>
</li>
<li>
<pre><code> else
</code></pre>
</li>
<li>
<pre><code> raise ArgumentError,
</code></pre>
</li>
<li>
<pre><code> "bad argument(expected URI object or URI string)"
</code></pre>
</li>
<li>
<pre><code> end
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> uris[0] = URI(uris[0], self)
uris.inject :merge
</code></pre>
end</li>
</ul>
<p>@@ -845,12 +838,12 @@ module Kernel<br>
#<br>
# Returns +uri+ converted to a URI object.<br>
#</p>
<ul>
<li>def URI(uri)</li>
</ul>
<ul>
<li>def URI(uri, parser = URI::DEFAULT_PARSER)<br>
case uri<br>
when URI::Generic<br>
uri<br>
when String</li>
</ul>
<ul>
<li>
<pre><code> URI.parse(uri)
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> parser.parse(uri)
</code></pre>
else<br>
raise ArgumentError,<br>
"bad argument (expected URI object or URI string)"<br>
diff --git a/lib/uri/generic.rb b/lib/uri/generic.rb<br>
index 4fdfd14..4084b56 100644<br>
--- a/lib/uri/generic.rb<br>
+++ b/lib/uri/generic.rb<br>
@@ -783,14 +783,7 @@ module URI
<a name="return-base-and-rel"></a>
<h1 >return base and rel.<a href="#return-base-and-rel" class="wiki-anchor">¶</a></h1>
<a name="you-can-modify-base-but-can-not-rel"></a>
<h1 >you can modify <code>base', but can not </code>rel'.<a href="#you-can-modify-base-but-can-not-rel" class="wiki-anchor">¶</a></h1>
def merge0(oth)</li>
</ul>
<ul>
<li>
<pre><code> case oth
</code></pre>
</li>
<li>
<pre><code> when Generic
</code></pre>
</li>
<li>
<pre><code> when String
</code></pre>
</li>
<li>
<pre><code> oth = parser.parse(oth)
</code></pre>
</li>
<li>
<pre><code> else
</code></pre>
</li>
<li>
<pre><code> raise ArgumentError,
</code></pre>
</li>
<li>
<pre><code> "bad argument(expected URI object or URI string)"
</code></pre>
</li>
<li>
<pre><code> end
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> oth = URI(oth, parser)
if self.relative? && oth.relative?
raise BadURIError,
</code></pre>
</li>
</ul>
<p>@@ -854,15 +847,7 @@ module URI<br>
private :route_from_path</p>
<pre><code> def route_from0(oth)
</code></pre>
<ul>
<li>
<pre><code> case oth
</code></pre>
</li>
<li>
<pre><code> when Generic
</code></pre>
</li>
<li>
<pre><code> when String
</code></pre>
</li>
<li>
<pre><code> oth = parser.parse(oth)
</code></pre>
</li>
<li>
<pre><code> else
</code></pre>
</li>
<li>
<pre><code> raise ArgumentError,
</code></pre>
</li>
<li>
<pre><code> "bad argument(expected URI object or URI string)"
</code></pre>
</li>
<li>
<pre><code> end
</code></pre>
</li>
<li>
</ul>
<ul>
<li>
<pre><code> oth = URI(oth, parser)
if self.relative?
raise BadURIError,
"relative URI: #{self}"
</code></pre>
</li>
</ul>
<p>@@ -966,16 +951,7 @@ module URI<br>
# #=> #<URI::Generic:0x2020c2f6 URL:/main.rbx?page=1><br>
#<br>
def route_to(oth)</p>
<ul>
<li>
<pre><code> case oth
</code></pre>
</li>
<li>
<pre><code> when Generic
</code></pre>
</li>
<li>
<pre><code> when String
</code></pre>
</li>
<li>
<pre><code> oth = parser.parse(oth)
</code></pre>
</li>
<li>
<pre><code> else
</code></pre>
</li>
<li>
<pre><code> raise ArgumentError,
</code></pre>
</li>
<li>
<pre><code> "bad argument(expected URI object or URI string)"
</code></pre>
</li>
<li>
<pre><code> end
</code></pre>
</li>
<li>
<li>
<pre><code> oth.route_from(self)
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> URI(oth, parser).route_from(self)
</code></pre>
<p>end</p>
<h1></h1>
</li>
</ul>
<p>=end</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 1.8 - Backport #3273 (Closed): Float string conversionhttps://bugs.ruby-lang.org/issues/32732010-05-11T14:12:19Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
For any float f, the two following conditions should hold:<br>
(1) f.to_s.to_f == f (round trips)<br>
(2) f.to_s.chop.to_f != f (minimal)</p>
<p>The second condition is a simplification; if the string representation is in scientific notation, than the character to remove would be the one just before the "e". Also, if the string representation ends with ".0", then it is minimal.</p>
<p>Currently, the first condition fails in Ruby 1.8, and the second fails in Ruby 1.9</p>
<p>$ ruby18dev -ve 'f = 0.21611564636388508; puts f.to_s.to_f == f'<br>
ruby 1.8.8dev (2010-05-11) [i386-darwin10.3.0]<br>
false</p>
<p>$ rubydev -ve 'f = 0.56; puts f.to_s.chop.to_f != f'<br>
ruby 1.9.3dev (2010-05-11 trunk 27730) [x86_64-darwin10.3.0]<br>
false</p>
<p>Note that this implies that Ruby 1.8 and 1.9 do not output the same string representation for either of these two floats.</p>
<p>The conversion algorithm currently checks two precisions. In Ruby 1.9, it tries 16 digits and if that's not enough it then uses 17. In 1.8, it's the same but with 15 and 16.</p>
<p>The fact is that 17 can be necessary (e.g. 0.21611564636388508 is not equal to either 0.2161156463638851 or 0.2161156463638850) and 16 can be too much (e.g. 0.5600000000000001 == 0.56), so three precisions must be checked.</p>
<p>The following patch fixes this issue for trunk (although it can probably be made nicer and/or faster).</p>
<p>Let me know if there are any objections to fixing both the 1.9 and 1.8 lines.</p>
<p>diff --git a/numeric.c b/numeric.c<br>
index f2c8c13..442b069 100644<br>
--- a/numeric.c<br>
+++ b/numeric.c<br>
@@ -569,7 +569,8 @@ flo_to_s(VALUE flt)<br>
else if (isnan(value))<br>
return rb_usascii_str_new2("NaN");</p>
<p>-# define FLOFMT(buf, size, fmt, prec, val) snprintf(buf, size, fmt, prec, val), <br>
+# define FLOFMT(buf, size, fmt, prec, val) snprintf(buf, size, fmt, prec-1, val), \</p>
<ul>
<li>
<p>(void)((atof(buf) == val) || snprintf(buf, size, fmt, (prec), val)), <br>
(void)((atof(buf) == val) || snprintf(buf, size, fmt, (prec)+1, val))</p>
<p>FLOFMT(buf, sizeof(buf), "%#.<em>g", float_dig, value); /</em> ensure to print decimal point */<br>
=end</p>
</li>
</ul> Ruby master - Feature #3222 (Closed): Can bignums have singleton class & methods?https://bugs.ruby-lang.org/issues/32222010-04-30T07:07:08Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Fixing up the rubyspecs led me to the following:</p>
<p>bn = 1 << 100<br>
class << bn<br>
def foo<br>
42<br>
end<br>
end</p>
<a name="gt-TypeError-cant-define-singleton-method-foo-for-Bignum"></a>
<h1 >=> TypeError: can't define singleton method "foo" for Bignum<a href="#gt-TypeError-cant-define-singleton-method-foo-for-Bignum" class="wiki-anchor">¶</a></h1>
<p>bn.define_singleton_method(:foo){42}</p>
<a name="gt-TypeError-cant-define-singleton-method-foo-for-Bignum-2"></a>
<h1 >=> TypeError: can't define singleton method "foo" for Bignum<a href="#gt-TypeError-cant-define-singleton-method-foo-for-Bignum-2" class="wiki-anchor">¶</a></h1>
<p>On the other hand...</p>
<p>module Bar<br>
def foo<br>
42<br>
end<br>
end<br>
class << bn<br>
include Bar<br>
end<br>
bn.foo # => 42</p>
<p>If Ruby won't allow singleton methods for Bignum, then shouldn't it disallow access to the singleton class completely?</p>
<p>See also issue <a class="issue tracker-1 status-5 priority-4 priority-default closed" title="Bug: an instance of Bignum can have singleton methods (Closed)" href="https://bugs.ruby-lang.org/issues/601">#601</a><br>
=end</p> Ruby master - Feature #3021 (Closed): Array#product should accept a block.https://bugs.ruby-lang.org/issues/30212010-03-27T02:59:16Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Array#permutation and #combination will yield to the given block, or else return an enumerator.</p>
<p>I believe Array#product should have been designed the same way.</p>
<p>Returning an enumerator today would break compatibility though.</p>
<p>I suggest that Array#product(&block) yields to the block and returns self. This maintains compatibility while making it possible to produce an enumerable with my_array.to_enum(:product, ...) or to avoid building an intermediate array.</p>
<p>I could implement this feature in time for code freeze.<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 #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 #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 - Feature #2451 (Closed): BasicObject.initialize with variable number of argumenthttps://bugs.ruby-lang.org/issues/24512009-12-07T10:18:32Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
If one wants to write a class easily extensible (for some kind of library, say), then there is no nice way to have the initialize method be extensible other than through monkeypatching.</p>
<p>This could be made much more flexible if BasicObject.initialize accepted any number of arguments.</p>
<p>Would there be a downsize to have BasicObject.initialize accept many arguments?</p>
<p>Here's a more detailed example:</p>
<p>class NiceClass<br>
def initialize(arg1, arg2)<br>
# do some stuff with arg1 and arg2<br>
super # allow for included modules to initialize<br>
end<br>
end</p>
<a name="Someone-else"></a>
<h1 >Someone else:<a href="#Someone-else" class="wiki-anchor">¶</a></h1>
<p>class NiceClass<br>
module CoolExtension<br>
def initialize(arg1, arg2)<br>
# do cool stuff<br>
super # allow for more extensions<br>
end<br>
end</p>
<p>include CoolExtension<br>
end</p>
<p>This would not work unless BasicObject#initialize accepts any number of arguments. Currently, only super() -- i.e. passing none of the arguments -- can be called, so arg1 & arg2 must be copied to instance variables for included modules to access, or else monkeypatching becomes the only possibility.</p>
<p>The patch is trivial:</p>
<p>diff --git a/object.c b/object.c<br>
index 10eb983..33cae20 100644<br>
--- a/object.c<br>
+++ b/object.c<br>
@@ -2538,7 +2538,7 @@ Init_Object(void)<br>
#undef rb_intern<br>
#define rb_intern(str) rb_intern_const(str)</p>
<ul>
<li>rb_define_private_method(rb_cBasicObject, "initialize", rb_obj_dummy, 0);</li>
</ul>
<ul>
<li>rb_define_private_method(rb_cBasicObject, "initialize", rb_obj_dummy, -1);<br>
rb_define_alloc_func(rb_cBasicObject, rb_class_allocate_instance);<br>
rb_define_method(rb_cBasicObject, "==", rb_obj_equal, 1);<br>
rb_define_method(rb_cBasicObject, "equal?", rb_obj_equal, 1);</li>
</ul>
<p>Notes:</p>
<ul>
<li>There is no documentation for BasicObject#initialize.</li>
<li>Ironically, the Ruby Draft Specification states that Object#initialize accepts any number of arguments! I'm glad I already have that team agree with me ;-)</li>
<li>No error is generated by make test-all</li>
<li>See also <a href="http://blog.rubybestpractices.com/posts/rklemme/018-Complete_Class.html" class="external">http://blog.rubybestpractices.com/posts/rklemme/018-Complete_Class.html</a> where Robert Klemme recommends calling super from constructors but has to use super(), i.e. passing no arguments</li>
</ul>
<p>Similarly, I also propose that Object#initialize accepts any number of arguments in Ruby 1.8.8<br>
=end</p> Backport187 - Backport #2450 (Closed): Array#sample can loop forever [patched]https://bugs.ruby-lang.org/issues/24502009-12-07T06:41:41Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
[:hello].sample(42) # ==> loops on Ruby 1.8.8</p>
<p>Fixed.</p>
<p>Other backports pass RubySpec.<br>
=end</p> Backport186 - Backport #2364 (Closed): Float conversion of NaN in 1.8.xhttps://bugs.ruby-lang.org/issues/23642009-11-14T09:36:10Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
Trying to fix issue <a class="issue tracker-4 status-5 priority-4 priority-default closed" title="Backport: lib/bigdecimal: errors in comparisons [patch] (Closed)" href="https://bugs.ruby-lang.org/issues/2349">#2349</a> for 1.8.8 but running into a small problem: conversion to a float will fail if the value converted corresponds to NaN:</p>
<p>$ ruby19 -r bigdecimal -e "p Float(BigDecimal('NaN'))"<br>
NaN<br>
$ ruby18 -r bigdecimal -e "p Float(BigDecimal('NaN'))"<br>
ArgumentError: invalid value for Float()</p>
<p>This is true of any class for which #to_f returns NaN.</p>
<p>This makes it impossible for BigDecimal("NaN") to be converted to a float in 1.8.</p>
<p>Can anyone think of a reason not to bring 1.8 inline with 1.9 (by allowing NaN)?</p>
<p>diff --git a/object.c b/object.c<br>
index 4704ebf..dd67039 100644<br>
--- a/object.c<br>
+++ b/object.c<br>
@@ -2486,13 +2486,7 @@ rb_Float(val)<br>
break;</p>
<pre><code> default:
</code></pre>
<ul>
<li>
<pre><code> {
</code></pre>
</li>
<li>
<pre><code> VALUE f = rb_convert_type(val, T_FLOAT, "Float", "to_f");
</code></pre>
</li>
<li>
<pre><code> if (isnan(RFLOAT(f)->value)) {
</code></pre>
</li>
<li>
<pre><code> rb_raise(rb_eArgError, "invalid value for Float()");
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<pre><code> return f;
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> return rb_convert_type(val, T_FLOAT, "Float", "to_f");
</code></pre>
}<br>
}</li>
</ul>
<p>(Doesn't generate any error in make test or test-all)<br>
=end</p> Backport186 - Backport #2349 (Closed): lib/bigdecimal: errors in comparisons [patch]https://bugs.ruby-lang.org/issues/23492009-11-09T15:33:34Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
$ ruby -r bigdecimal -e 'p BigDecimal.new("1") < nil'<br>
nil</p>
<p>expected: an error like with any other mathematical type:<br>
-e:1:in `<': comparison of BigDecimal with nil failed (ArgumentError)</p>
<hr>
<p>$ ruby -r bigdecimal -e 'p BigDecimal.new("1") == nil'<br>
nil</p>
<p>expected: false like with any other Ruby object</p>
<hr>
<p>$ ruby -r bigdecimal -e 'p BigDecimal.new("NaN") < 1'<br>
nil</p>
<p>expected: false, like with any other mathematical comparison</p>
<p>I'll commit the attached patch in a few days (for 1.8 & 1.9) unless there are arguments against it.<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 #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 - Feature #2172 (Closed): Enumerable#chunk with no blockhttps://bugs.ruby-lang.org/issues/21722009-10-03T13:48:45Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
What should "(1..3).chunk" (i.e. without a block) do?</p>
<p>It issued an<br>
ArgumentError: tried to create Proc object without a block</p>
<p>I changed the error message to "no block given" which I hope to be more informative, but maybe there is something more useful to do here?</p>
<p>A default block of {|x| x} doesn't seem all that useful.</p>
<p>Returning an enumerator that, upon completion, will return an enumerator would probably be better, but could also be a bit confusing if someone doesn't realize he forgot to specify the block?</p>
<p>Thanks to Run Paint for raising the question when writing the rubyspec for #chunk.<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 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 - Feature #1667 (Closed): IO#codepoints, IO#each_codepoint, and StringIOhttps://bugs.ruby-lang.org/issues/16672009-06-20T21:47:52Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>Almost all "iterators" of <code>String</code> are present in <code>IO</code> and <code>StringIO</code>: <code>#each_char</code>, <code>#each_byte</code>, <code>#each_line</code> and their corresponding <code>#chars</code>, <code>#bytes</code>, <code>#lines</code>. Only <code>#each_codepoint</code> and <code>#codepoints</code> are not defined in <code>IO</code> and <code>StringIO</code>.</p>
<p>Unless there is a compelling reason not to, it would be useful if these were defined. This would mirror the coherence with all other <code>each_</code>* methods that exist in both <code>String</code>, <code>IO</code> and <code>StringIO</code>.</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 #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> Ruby master - Feature #666 (Rejected): Enumerable::to_hashhttps://bugs.ruby-lang.org/issues/6662008-10-20T14:25:23Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<p>=begin<br>
There are many ways to obtain an array from enumerables (to_a, map, ...).<br>
There is no natural way to obtain a hash from an enumerable (except for Hash[some_array]).<br>
There is a Hash::to_a but no Array::to_hash.<br>
Here is what I would like:</p>
<p>[[:hello, "world"], [:choice, [:red_pill, :blue_pill]]].to_hash ==> {:hello=>"world", :choice=>[:red_pill, :blue_pill]}<br>
(1..3).to_hash{|n| [n, n**2]} ==> {1 => 1, 2 ==> 4, 3 ==> 9}</p>
<p>I propose to add the following Enumerable::to_hash :</p>
<p>module Enumerable<br>
def to_hash<br>
result = {}<br>
self.each do |key, value|<br>
key, value = yield(key, value) if block_given?<br>
result[key] = value<br>
end<br>
result<br>
end<br>
end</p>
<p>Since Hash::to_a returns an array of key-value pairs, I fell it's natural that a block to construct a Hash should return key-value pairs.<br>
This definition has nice symmetric properties: for any Hash h, the following all return a copy of h.<br>
h.to_a.to_hash<br>
h.to_hash{|p| p}<br>
h.to_hash{|k,v| [k,v]}<br>
h.keys.zip(h.values).to_hash</p>
<p>Thank you for your attention,</p>
<p>Marc-Andre Lafortune<br>
=end</p>