https://redmine.ruby-lang.org/https://redmine.ruby-lang.org/favicon.ico?17113305112020-04-23T20:04:40ZRuby Issue Tracking SystemRuby master - Feature #16812: Allow slicing arrays with ArithmeticSequencehttps://redmine.ruby-lang.org/issues/16812?journal_id=852652020-04-23T20:04:40ZEregon (Benoit Daloze)
<ul></ul><p>Rather neutral on this, but would you want that to work for <code>Array#[]=</code> too?<br>
I would be against <code>Array#[]=</code> as it's already so complicated and that would just make it a lot more so.</p>
<p>In <code>Array#[]</code> it's probably fine though.</p> Ruby master - Feature #16812: Allow slicing arrays with ArithmeticSequencehttps://redmine.ruby-lang.org/issues/16812?journal_id=852662020-04-23T20:44:42Zzverok (Victor Shepelev)zverok.offline@gmail.com
<ul></ul><p><a class="user active user-mention" href="https://redmine.ruby-lang.org/users/772">@Eregon (Benoit Daloze)</a>, I wanted at first to see what people say about this one :)</p>
<p><code>Array#[]=</code> is a thing that should be kinda "symmetric", but playing a bit with it, I understood that I am afraid of trying to guess what would be "logical".</p>
<p>Honestly, I can't remember I've ever used a form like <code>a[1..3] = 'x'</code>, and its behavior is kinda "theoretically logical", but at the same time only one of the things you may "intuitively" expect ("replace all three elements with one, changing array's size" wouldn't be my first guess...).</p>
<p>So, at least for now, my only proposal is <code>Array#[]</code>.</p> Ruby master - Feature #16812: Allow slicing arrays with ArithmeticSequencehttps://redmine.ruby-lang.org/issues/16812?journal_id=852672020-04-24T00:19:35ZDan0042 (Daniel DeLorme)
<ul></ul><p>Theoretically I'm in favor but there's some edge cases that need consideration.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">nums</span> <span class="o">=</span> <span class="p">(</span><span class="mi">0</span><span class="o">..</span><span class="mi">20</span><span class="p">).</span><span class="nf">to_a</span>
<span class="n">s</span> <span class="o">=</span> <span class="mi">10</span><span class="p">.</span><span class="nf">step</span><span class="p">(</span><span class="ss">by: </span><span class="o">-</span><span class="mi">2</span><span class="p">)</span> <span class="c1"># 10, 8, 6, 4, 2, 0, -2, ...</span>
<span class="n">nums</span><span class="p">[</span><span class="n">s</span><span class="p">]</span> <span class="c1">#=> [10, 8, 6, 4, 2, 0, 19, 17, ...] ???</span>
<span class="n">s</span> <span class="o">=</span> <span class="p">(</span><span class="o">-</span><span class="mi">5</span><span class="o">..</span><span class="mi">5</span><span class="p">)</span> <span class="o">%</span> <span class="mi">2</span> <span class="c1"># -5, -3, -1, 1, 3, 5</span>
<span class="n">nums</span><span class="p">[</span><span class="n">s</span><span class="p">]</span> <span class="c1">#=> [16, 18, 20, 1, 3, 5] ???</span>
</code></pre> Ruby master - Feature #16812: Allow slicing arrays with ArithmeticSequencehttps://redmine.ruby-lang.org/issues/16812?journal_id=852712020-04-24T04:08:02Znobu (Nobuyoshi Nakada)nobu@ruby-lang.org
<ul></ul><p>A few bugs.</p>
<ul>
<li>
<p><code>Float</code> <code>ArithmeticSequence</code> crashes.</p>
<pre><code class="shell syntaxhl" data-language="shell"><span class="nv">$ </span>./ruby <span class="nt">-e</span> <span class="s1">'[*0..10][(0.0..)%10]'</span>
Assertion Failed: ../src/include/ruby/3/arithmetic/long.h:136:ruby3_fix2long_by_shift:<span class="s2">"RB_FIXNUM_P(x)"</span>
</code></pre>
</li>
<li>
<p>If overridden <code>take_while</code> (and <code>drop_while</code>) returns non-<code>Array</code>, crashes.</p>
<pre><code class="shell syntaxhl" data-language="shell"><span class="nv">$ </span>./ruby <span class="s1">'a = (1..10)%2; def a.take_while; nil; end; [*1..10][a]'</span>
<span class="nt">-e</span>:1:in <span class="sb">`</span><main><span class="s1">': wrong argument type nil (expected Array) (TypeError)
</span></code></pre>
</li>
</ul>
<p>These resulted in assertion failures, but would segfault when compiled with <code>NDEBUG</code>.</p> Ruby master - Feature #16812: Allow slicing arrays with ArithmeticSequencehttps://redmine.ruby-lang.org/issues/16812?journal_id=852722020-04-24T05:09:40Zmrkn (Kenta Murata)muraken@gmail.com
<ul><li><strong>Status</strong> changed from <i>Open</i> to <i>Assigned</i></li><li><strong>Assignee</strong> set to <i>matz (Yukihiro Matsumoto)</i></li></ul><p>I'm positive this if the behavior is the same as Python's list slicing.<br>
If the behavior will be different from Python's, I'm negative because it confuses PyCall users.</p> Ruby master - Feature #16812: Allow slicing arrays with ArithmeticSequencehttps://redmine.ruby-lang.org/issues/16812?journal_id=852912020-04-25T17:48:40Zzverok (Victor Shepelev)zverok.offline@gmail.com
<ul></ul><p>As there is no immediate rejection, I updated the implementation, making it more robust.</p>
<p><a class="user active user-mention" href="https://redmine.ruby-lang.org/users/11019">@Dan0042 (Daniel DeLorme)</a>, I tried to make edge cases consistent, so now they are...</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="p">(</span><span class="mi">0</span><span class="o">..</span><span class="mi">20</span><span class="p">).</span><span class="nf">to_a</span><span class="p">[</span><span class="mi">10</span><span class="p">.</span><span class="nf">step</span><span class="p">(</span><span class="ss">by: </span><span class="o">-</span><span class="mi">2</span><span class="p">)]</span>
<span class="c1"># => [10, 8, 6, 4, 2, 0] -- avoids weird cycling</span>
<span class="p">(</span><span class="mi">0</span><span class="o">..</span><span class="mi">20</span><span class="p">).</span><span class="nf">to_a</span><span class="p">[(</span><span class="o">-</span><span class="mi">5</span><span class="o">..</span><span class="mi">5</span><span class="p">)</span> <span class="o">%</span> <span class="mi">2</span><span class="p">]</span>
<span class="c1"># => [] -- this is consistent with</span>
<span class="p">(</span><span class="mi">0</span><span class="o">..</span><span class="mi">20</span><span class="p">).</span><span class="nf">to_a</span><span class="p">[</span><span class="o">-</span><span class="mi">5</span><span class="o">..</span><span class="mi">5</span><span class="p">]</span> <span class="c1"># which can be thought as (-5..5) % 1</span>
<span class="c1"># => [] </span>
<span class="c1"># Note, though:</span>
<span class="p">(</span><span class="mi">0</span><span class="o">..</span><span class="mi">20</span><span class="p">).</span><span class="nf">to_a</span><span class="p">[</span><span class="o">-</span><span class="mi">19</span><span class="o">..</span><span class="mi">5</span><span class="p">]</span>
<span class="c1"># => [2, 3, 4, 5] -- not literally "from -19 to 5", but "from 19th from the end to 5th from the beginning"</span>
<span class="c1"># ...so...</span>
<span class="p">(</span><span class="mi">0</span><span class="o">..</span><span class="mi">20</span><span class="p">).</span><span class="nf">to_a</span><span class="p">[(</span><span class="o">-</span><span class="mi">19</span><span class="o">..</span><span class="mi">5</span><span class="p">)</span><span class="o">%</span><span class="mi">2</span><span class="p">]</span>
<span class="c1"># => [2, 4]</span>
</code></pre>
<p><a class="user active user-mention" href="https://redmine.ruby-lang.org/users/4">@nobu (Nobuyoshi Nakada)</a> I've tried to fix bugs. Now float begin/end is processed correctly, float step is TypeError, and the code does not rely on <code>#take_while</code>/<code>#drop_while</code>.</p>
<p><a class="user active user-mention" href="https://redmine.ruby-lang.org/users/482">@mrkn (Kenta Murata)</a> I've checked against Python impl, and believe the behavior is mostly the same. One difference I am aware of is this:</p>
<p>Python:</p>
<pre><code class="python syntaxhl" data-language="python"><span class="nf">list</span><span class="p">(</span><span class="nf">range</span><span class="p">(</span><span class="mi">10</span><span class="p">))[</span><span class="o">-</span><span class="mi">100</span><span class="p">:</span><span class="mi">100</span><span class="p">:</span><span class="mi">2</span><span class="p">]</span>
<span class="c1">#=> [0, 2, 4, 6, 8]
</span></code></pre>
<p>Ruby:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="p">[</span><span class="o">*</span><span class="mi">0</span><span class="o">..</span><span class="mi">10</span><span class="p">][(</span><span class="o">-</span><span class="mi">100</span><span class="o">..</span><span class="mi">100</span><span class="p">)</span><span class="o">%</span><span class="mi">2</span><span class="p">]</span>
<span class="c1"># => nil</span>
</code></pre>
<p>That's because first of all I wanted to make it consistent with</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="p">[</span><span class="o">*</span><span class="mi">0</span><span class="o">..</span><span class="mi">10</span><span class="p">][</span><span class="o">-</span><span class="mi">100</span><span class="o">..</span><span class="mi">100</span><span class="p">]</span>
<span class="c1"># => nil</span>
</code></pre>
<p>...which may be questioned (like, "range from -100 to 100 includes 0..10, so it should fetch entire array"), but that's how it is now :)</p> Ruby master - Feature #16812: Allow slicing arrays with ArithmeticSequencehttps://redmine.ruby-lang.org/issues/16812?journal_id=862092020-06-18T02:06:17Zmrkn (Kenta Murata)muraken@gmail.com
<ul></ul><p>It may be better to change the behavior of <code>[*0..10][-100..100]</code> because <code>[*0..10][..100]</code> does not return <code>nil</code>:</p>
<pre><code>[*0..10][..100]
# => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
</code></pre>
<p>And the following cases seems inconsistent to me:</p>
<pre><code>[*0..10][0..12]
# => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[*0..10][-12..-1]
# => nil
</code></pre> Ruby master - Feature #16812: Allow slicing arrays with ArithmeticSequencehttps://redmine.ruby-lang.org/issues/16812?journal_id=862632020-06-19T14:12:28Zmrkn (Kenta Murata)muraken@gmail.com
<ul></ul><p>I made a patch: <a href="https://github.com/ruby/ruby/pull/3241" class="external">https://github.com/ruby/ruby/pull/3241</a></p> Ruby master - Feature #16812: Allow slicing arrays with ArithmeticSequencehttps://redmine.ruby-lang.org/issues/16812?journal_id=863392020-06-26T19:08:11ZDan0042 (Daniel DeLorme)
<ul></ul><p>mrkn (Kenta Murata) wrote in <a href="#note-7">#note-7</a>:</p>
<blockquote>
<p>It may be better to change the behavior of <code>[*0..10][-100..100]</code></p>
</blockquote>
<p>I somewhat agree with that. When using range slicing most combinations make sense:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="p">[</span><span class="o">*</span><span class="mi">0</span><span class="o">..</span><span class="mi">10</span><span class="p">][</span><span class="mi">0</span><span class="o">..</span><span class="mi">4</span><span class="p">]</span> <span class="c1">#first elements</span>
<span class="p">[</span><span class="o">*</span><span class="mi">0</span><span class="o">..</span><span class="mi">10</span><span class="p">][</span><span class="o">-</span><span class="mi">5</span><span class="o">..-</span><span class="mi">1</span><span class="p">]</span> <span class="c1">#last elements</span>
<span class="p">[</span><span class="o">*</span><span class="mi">0</span><span class="o">..</span><span class="mi">10</span><span class="p">][</span><span class="mi">1</span><span class="o">..-</span><span class="mi">2</span><span class="p">]</span> <span class="c1">#middle elements</span>
</code></pre>
<p>But a negative start with a non-negative end is quite weird. What is that operation even supposed to mean? What is it useful for?</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="p">[</span><span class="o">*</span><span class="mi">0</span><span class="o">..</span><span class="mi">10</span><span class="p">][</span><span class="o">-</span><span class="mi">8</span><span class="o">..</span><span class="mi">8</span><span class="p">]</span> <span class="c1">#????</span>
<span class="mi">8</span><span class="p">.</span><span class="nf">times</span><span class="p">{</span> <span class="o">|</span><span class="n">i</span><span class="o">|</span> <span class="nb">p</span> <span class="p">(</span><span class="mi">0</span><span class="o">..</span><span class="n">i</span><span class="p">)</span> <span class="o">=></span> <span class="p">[</span><span class="o">*</span><span class="mi">0</span><span class="o">..</span><span class="n">i</span><span class="p">][</span><span class="o">-</span><span class="mi">3</span><span class="o">..</span><span class="mi">3</span><span class="p">]</span> <span class="p">}</span>
<span class="p">{</span><span class="mi">0</span><span class="o">..</span><span class="mi">0</span><span class="o">=></span><span class="kp">nil</span><span class="p">}</span>
<span class="p">{</span><span class="mi">0</span><span class="o">..</span><span class="mi">1</span><span class="o">=></span><span class="kp">nil</span><span class="p">}</span>
<span class="p">{</span><span class="mi">0</span><span class="o">..</span><span class="mi">2</span><span class="o">=></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="mi">2</span><span class="p">]}</span>
<span class="p">{</span><span class="mi">0</span><span class="o">..</span><span class="mi">3</span><span class="o">=></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="p">{</span><span class="mi">0</span><span class="o">..</span><span class="mi">4</span><span class="o">=></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="p">{</span><span class="mi">0</span><span class="o">..</span><span class="mi">5</span><span class="o">=></span><span class="p">[</span><span class="mi">3</span><span class="p">]}</span>
<span class="p">{</span><span class="mi">0</span><span class="o">..</span><span class="mi">6</span><span class="o">=></span><span class="p">[]}</span>
<span class="p">{</span><span class="mi">0</span><span class="o">..</span><span class="mi">7</span><span class="o">=></span><span class="p">[]}</span>
</code></pre>
<p>So even if <code>[*0..10][-100..100]</code> remains supported forever (there doesn't seem to be a point in breaking compatibility; see <a class="issue tracker-2 status-6 priority-4 priority-default closed" title="Feature: Array slicing: nils and edge cases (Rejected)" href="https://redmine.ruby-lang.org/issues/16822">#16822</a>), it could emit a verbose-mode warning.<br>
And ArithmeticSequence slicing should not attempt to be consistent with that case, because it's useless to start with.<br>
So I believe there are two useful/meaningful possibilities for <code>(0..20).to_a[(-5..5) % 2]</code><br>
a) <code>[16, 18, 20]</code> ignore trailing non-negative values, like <code>(-5..) % 2</code>; I think this makes the most sense<br>
b) <code>[1, 3, 5]</code> ignore leading negative values, like python</p> Ruby master - Feature #16812: Allow slicing arrays with ArithmeticSequencehttps://redmine.ruby-lang.org/issues/16812?journal_id=863592020-06-27T09:14:48Zzverok (Victor Shepelev)zverok.offline@gmail.com
<ul></ul><blockquote>
<p>But a negative start with a non-negative end is quite weird. What is that operation even supposed to mean? What is it useful for?</p>
</blockquote>
<p>I believe such edge cases might emerge not being directly written, but when dynamically calculated. Imagine calculating some anchor element, and then taking N elements around it. Then, you have, say...</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">around_mean</span><span class="p">(</span><span class="n">ary</span><span class="p">,</span> <span class="ss">count: </span><span class="mi">3</span><span class="p">)</span>
<span class="n">i</span> <span class="o">=</span> <span class="n">ary</span><span class="p">.</span><span class="nf">index</span><span class="p">(</span><span class="n">ary</span><span class="p">.</span><span class="nf">sum</span> <span class="o">/</span> <span class="n">ary</span><span class="p">.</span><span class="nf">length</span><span class="p">)</span>
<span class="n">ary</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="n">count</span><span class="o">..</span><span class="n">i</span><span class="o">+</span><span class="n">count</span><span class="p">]</span>
<span class="k">end</span>
<span class="n">around_mean</span><span class="p">((</span><span class="mi">1</span><span class="o">..</span><span class="mi">20</span><span class="p">).</span><span class="nf">to_a</span><span class="p">)</span>
<span class="c1"># => [7, 8, 9, 10, 11, 12, 13] </span>
<span class="n">around_mean</span><span class="p">((</span><span class="mi">1</span><span class="o">..</span><span class="mi">6</span><span class="p">).</span><span class="nf">to_a</span><span class="p">)</span>
<span class="c1"># => [6] -- hm, it is a bit strange</span>
<span class="n">around_mean</span><span class="p">((</span><span class="mi">1</span><span class="o">..</span><span class="mi">6</span><span class="p">).</span><span class="nf">to_a</span><span class="p">,</span> <span class="ss">count: </span><span class="mi">10</span><span class="p">)</span>
<span class="c1"># => nil -- hm, it is even weirder...</span>
</code></pre>
<p>The example before last is <code>[1, 2, 3, 4, 5, 6][-1..5]</code> which "intuitively weird", as one <em>might</em> expect something like:</p>
<pre><code> 1 2 3 4 5 6
^^^^^^^^^^^
</code></pre>
<p>The very last example is <code>[1, 2, 3, 4, 5, 6][-8..12]</code> -- and it even doesn't produce empty array (I pointed at this at <a class="issue tracker-2 status-6 priority-4 priority-default closed" title="Feature: Array slicing: nils and edge cases (Rejected)" href="https://redmine.ruby-lang.org/issues/16822">#16822</a>, too).</p>
<p>That's not the best possible example, but at least it demonstrates how we can arrive at edge case situation and why we (probably) might expect different behavior here.</p> Ruby master - Feature #16812: Allow slicing arrays with ArithmeticSequencehttps://redmine.ruby-lang.org/issues/16812?journal_id=866202020-07-20T07:04:23Zmatz (Yukihiro Matsumoto)matz@ruby.or.jp
<ul></ul><p>The basic bahavior seems OK. Probably we need to investigate some corner cases, but you can commit (and we experiment).</p>
<p>Matz.</p> Ruby master - Feature #16812: Allow slicing arrays with ArithmeticSequencehttps://redmine.ruby-lang.org/issues/16812?journal_id=880662020-10-20T17:40:34ZAnonymous
<ul><li><strong>Status</strong> changed from <i>Assigned</i> to <i>Closed</i></li></ul><p>Applied in changeset <a class="changeset" title="Feature #16812: Allow slicing arrays with ArithmeticSequence (#3241) * Support ArithmeticSequenc..." href="https://redmine.ruby-lang.org/projects/ruby-master/repository/git/revisions/a6a8576e877b02b83cabd0e712ecd377e7bc156b">git|a6a8576e877b02b83cabd0e712ecd377e7bc156b</a>.</p>
<hr>
<p>Feature <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: Allow slicing arrays with ArithmeticSequence (Closed)" href="https://redmine.ruby-lang.org/issues/16812">#16812</a>: Allow slicing arrays with ArithmeticSequence (#3241)</p>
<ul>
<li>
<p>Support ArithmeticSequence in Array#slice</p>
</li>
<li>
<p>Extract rb_range_component_beg_len</p>
</li>
<li>
<p>Use rb_range_values to check Range object</p>
</li>
<li>
<p>Fix ary_make_partial_step</p>
</li>
<li>
<p>Fix for negative step cases</p>
</li>
<li>
<p>range.c: Describe the role of err argument in rb_range_component_beg_len</p>
</li>
<li>
<p>Raise a RangeError when an arithmetic sequence refers the outside of an array</p>
</li>
</ul>
<p>[Feature <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: Allow slicing arrays with ArithmeticSequence (Closed)" href="https://redmine.ruby-lang.org/issues/16812">#16812</a>]</p>