https://bugs.ruby-lang.org/https://bugs.ruby-lang.org/favicon.ico?17113305112019-10-22T16:29:18ZRuby Issue Tracking SystemRuby master - Bug #16270: Strange behavior on Hash's #each and #select method.https://bugs.ruby-lang.org/issues/16270?journal_id=822362019-10-22T16:29:18Zshevegen (Robert A. Heiler)shevegen@gmail.com
<ul></ul><p>I am not entirely sure where there is a lack of consistency or why the<br>
C code is necessary. I assume that you may have been confused about<br>
Kernel#p perhaps? It is rare that people combine .select with p,<br>
whereas this behaviour is more frequently seen with .each, where people<br>
may output all or some elements.</p>
<p>What helps me personally is when I "split" up the Hash into "key" and<br>
"value" pairs, such as:</p>
<pre><code>sample_hash.select {|key, value| p key }
</code></pre>
<p>The above still does not make a whole lot of sense to me, but from the<br>
code alone I think it became more clear what you, as a user of ruby,<br>
actually want to do. Of course I may have misunderstood you as well.</p>
<p>(The reason why I wrote that I do not see a lack of consistency is because<br>
.each and .select have different behaviour on purpose. What I often do<br>
is modify the internal dataset of a class, before I may then go on to<br>
report it to the user after the dataset was modified. It's a bit like MVC<br>
but nowhere as strict as MVC separates stuff.)</p> Ruby master - Bug #16270: Strange behavior on Hash's #each and #select method.https://bugs.ruby-lang.org/issues/16270?journal_id=822372019-10-22T16:31:20Zjeremyevans0 (Jeremy Evans)merch-redmine@jeremyevans.net
<ul><li><strong>Status</strong> changed from <i>Open</i> to <i>Closed</i></li></ul><p>You need to look at the functions passed to <code>rb_hash_foreach</code>:</p>
<pre><code class="c syntaxhl" data-language="c"><span class="k">static</span> <span class="kt">int</span>
<span class="nf">each_pair_i</span><span class="p">(</span><span class="n">VALUE</span> <span class="n">key</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">value</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">_</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">rb_yield</span><span class="p">(</span><span class="n">rb_assoc_new</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="k">return</span> <span class="n">ST_CONTINUE</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">static</span> <span class="kt">int</span>
<span class="nf">select_i</span><span class="p">(</span><span class="n">VALUE</span> <span class="n">key</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">value</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">result</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">RTEST</span><span class="p">(</span><span class="n">rb_yield_values</span><span class="p">(</span><span class="mi">2</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="p">{</span>
<span class="n">rb_hash_aset</span><span class="p">(</span><span class="n">result</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="p">}</span>
<span class="k">return</span> <span class="n">ST_CONTINUE</span><span class="p">;</span>
<span class="p">}</span>
</code></pre>
<p><code>each_pair_i</code> yields a single array argument with the key and the value, <code>select_i</code> yields 2 arguments (key and value separately).</p>
<p>This is inconsistent, and could potentially be changed so that blocks passed to <code>Hash#select</code> that accept a single argument are yielded an array. However, that may cause backwards compatibility issues with existing code that expects the key to be yielded to the block (instead of an array with the key and value).</p>
<p>I don't think the current behavior is a bug, so I'm going to close this. If you would like <code>Hash#select</code> behavior changed when passing a block that accepts a single argument, please submit a feature request for that.</p> Ruby master - Bug #16270: Strange behavior on Hash's #each and #select method.https://bugs.ruby-lang.org/issues/16270?journal_id=822382019-10-22T16:47:27Zsawa (Tsuyoshi Sawada)
<ul><li><strong>Description</strong> updated (<a title="View differences" href="/journals/82238/diff?detail_id=55434">diff</a>)</li></ul> Ruby master - Bug #16270: Strange behavior on Hash's #each and #select method.https://bugs.ruby-lang.org/issues/16270?journal_id=822402019-10-22T17:41:14ZDan0042 (Daniel DeLorme)
<ul></ul><p>Of all Hash methods, only select/reject/select!/reject!/keep_if/delete_if have that behavior. That's fairly inconsistent, but more importantly it doesn't seem like this inconsistency is on purpose. There is no test for this case in test/ruby/test_hash.rb.</p>
<p>I tried changing <code>rb_yield_values(2</code> to <code>rb_yield(rb_assoc_new(</code> and I got only one failure in the specs, in test_delete_if, because of <code>h.delete_if {|*a|</code> where <code>*a</code> becomes <code>[[1,"one"]]</code> instead of <code>[1,"one"]</code>. And that is more related to <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: Remove exceptional treatment of *foo when it is the sole block parameter (Closed)" href="https://bugs.ruby-lang.org/issues/16166">#16166</a> than the current issue.</p>