https://redmine.ruby-lang.org/https://redmine.ruby-lang.org/favicon.ico?17113305112014-11-12T15:31:37ZRuby Issue Tracking SystemRuby master - Feature #10498: Make `loop` yield a counterhttps://redmine.ruby-lang.org/issues/10498?journal_id=499162014-11-12T15:31:37Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<ul></ul><p>I've also expected <code>loop</code> to yield a number and forget from time to time it doesn't.</p>
<p>Note you can achieve the same effect today with <code>(0..Float::INFINITY).each</code>. It's explicit, but quite a bit longer.</p> Ruby master - Feature #10498: Make `loop` yield a counterhttps://redmine.ruby-lang.org/issues/10498?journal_id=499172014-11-12T15:37:52Zchrisseaton (Chris Seaton)chris@chrisseaton.com
<ul></ul><p>But doesn't this mean #loop will only run FIXNUM_MAX times? Rather than run infinitely as it currently does? That's a pretty big semantic change. Also, why not just overflow to Bignum?</p> Ruby master - Feature #10498: Make `loop` yield a counterhttps://redmine.ruby-lang.org/issues/10498?journal_id=499182014-11-12T16:09:47Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<ul></ul><p>Chris Seaton wrote:</p>
<blockquote>
<p>But doesn't this mean #loop will only run FIXNUM_MAX times?</p>
</blockquote>
<p>Indeed, the patch is not acceptable.</p>
<p>Let's consider the feature request that loop infinitely and yields a number (that will eventually be a Bignum). If this is accepted, writing the patch won't be a big issue.</p>
<p>I forgot another existing alternative: <code>loop.with_index do |_, i|</code> gets the same effect.</p> Ruby master - Feature #10498: Make `loop` yield a counterhttps://redmine.ruby-lang.org/issues/10498?journal_id=499222014-11-13T01:44:27Zduerst (Martin Dürst)duerst@it.aoyama.ac.jp
<ul></ul><p>Shouldn't the version of loop that yields a number be called loop_with_index, to correspond with others such as each_with_index, map_with_index, and so forth? Maybe with a little bit of magic, that can be made to happen?</p> Ruby master - Feature #10498: Make `loop` yield a counterhttps://redmine.ruby-lang.org/issues/10498?journal_id=499302014-11-13T08:12:08Znobu (Nobuyoshi Nakada)nobu@ruby-lang.org
<ul><li><strong>Description</strong> updated (<a title="View differences" href="/journals/49930/diff?detail_id=36018">diff</a>)</li></ul> Ruby master - Feature #10498: Make `loop` yield a counterhttps://redmine.ruby-lang.org/issues/10498?journal_id=499572014-11-14T22:28:06Zcesario (Franck Verrot)franck@verrot.fr
<ul><li><strong>File</strong> <a href="/attachments/4871">0001-vm_eval.c-loop-now-yields-a-incremented-counter.patch</a> <a class="icon-only icon-download" title="Download" href="/attachments/download/4871/0001-vm_eval.c-loop-now-yields-a-incremented-counter.patch">0001-vm_eval.c-loop-now-yields-a-incremented-counter.patch</a> added</li></ul><p>Marc-Andre Lafortune wrote:</p>
<blockquote>
<p>Chris Seaton wrote:</p>
<blockquote>
<p>But doesn't this mean #loop will only run FIXNUM_MAX times?</p>
</blockquote>
<p>Indeed, the patch is not acceptable.</p>
</blockquote>
<p>This indeed was a mistake, I've re-submitted a new patch.</p>
<p>So now the counter starts at 0 and will eventually become a Bignum when bigger than FIXNUM_MAX.</p> Ruby master - Feature #10498: Make `loop` yield a counterhttps://redmine.ruby-lang.org/issues/10498?journal_id=499582014-11-14T22:42:24Zphluid61 (Matthew Kerwin)matthew@kerwin.net.au
<ul></ul><p>I agree with Martin, this should be Kernel#loop_with_index</p> Ruby master - Feature #10498: Make `loop` yield a counterhttps://redmine.ruby-lang.org/issues/10498?journal_id=499602014-11-14T23:35:33Zcesario (Franck Verrot)franck@verrot.fr
<ul></ul><p>Martin Dürst wrote:</p>
<blockquote>
<p>Shouldn't the version of loop that yields a number be called loop_with_index, to correspond with others such as each_with_index, map_with_index, and so forth? Maybe with a little bit of magic, that can be made to happen?</p>
</blockquote>
<p>I might have overlooked them, but I can't find any reference to any other<code>*_with_index</code> method than <code>each_with_index</code>. Are they in Ruby core or in an external gem?</p> Ruby master - Feature #10498: Make `loop` yield a counterhttps://redmine.ruby-lang.org/issues/10498?journal_id=499632014-11-15T12:39:51Zjoffreyjaffeux (Joffrey Jaffeux)j.jaffeux@gmail.com
<ul></ul><p>Franck Verrot wrote:</p>
<blockquote>
<p>I might have overlooked them, but I can't find any reference to any other<code>*_with_index</code> method than <code>each_with_index</code>. Are they in Ruby core or in an external gem?</p>
</blockquote>
<p><code>each_with_index</code> does exist, but concerning <code>map</code>, Martin was probably talking about <code>map.with_index</code> as defined in <a href="http://ruby-doc.org/core-2.1.5/Enumerator.html#method-i-with_index" class="external">http://ruby-doc.org/core-2.1.5/Enumerator.html#method-i-with_index</a></p>
<p>Using <code>loop.with_index {|i| puts i}</code> will currently yield nil.</p> Ruby master - Feature #10498: Make `loop` yield a counterhttps://redmine.ruby-lang.org/issues/10498?journal_id=499762014-11-16T10:48:27Zfunny_falcon (Yura Sokolov)funny.falcon@gmail.com
<ul></ul><pre><code>> loop.with_index.take(10)
=> [[nil, 0], [nil, 1], [nil, 2], [nil, 3], [nil, 4], [nil, 5], [nil, 6], [nil, 7], [nil, 8], [nil, 9]]
> loop.with_index{|_,i| p i; break}
0
=> nil
</code></pre> Ruby master - Feature #10498: Make `loop` yield a counterhttps://redmine.ruby-lang.org/issues/10498?journal_id=499772014-11-16T10:52:43Zfunny_falcon (Yura Sokolov)funny.falcon@gmail.com
<ul></ul><pre><code>> LOOP = 2**1000
=> 10715086071862673209484250490600018105614048117055336074437503883703510511249361224931983788156958581275946729175531468251871452856923140435984577574698574803934567774824230985421074605062371141877954182153046474983581941267398767559165543946077062914571196477686542167660429831652624386837205668069376
> LOOP.times.take(10)
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
> LOOP.times{|i| p i; break if i == 2}
0
1
2
=> nil
</code></pre>
<p>But still, if <code>loop</code> yields index it will not damage anyone.</p> Ruby master - Feature #10498: Make `loop` yield a counterhttps://redmine.ruby-lang.org/issues/10498?journal_id=499852014-11-17T07:51:36Zrecursive-madman (Recursive Madman)recursive.madman@gmx.de
<ul></ul><blockquote>
<p>But still, if <code>loop</code> yields index it will not damage anyone.</p>
</blockquote>
<p>If existing code passes a lambda (or anything else with argument checking), it would damage them.</p>
<p>I think having loop yield a counter is very useful, but it should check <code>#arity != 0</code> for backwards compatibility.</p> Ruby master - Feature #10498: Make `loop` yield a counterhttps://redmine.ruby-lang.org/issues/10498?journal_id=499862014-11-17T09:42:42Zfunny_falcon (Yura Sokolov)funny.falcon@gmail.com
<ul></ul><blockquote>
<p>I think having loop yield a counter is very useful, but it should check #arity != 0 for backwards compatibility.</p>
</blockquote>
<p>You are right. +1</p> Ruby master - Feature #10498: Make `loop` yield a counterhttps://redmine.ruby-lang.org/issues/10498?journal_id=499872014-11-17T13:12:26Zznz (Kazuhiro NISHIYAMA)
<ul></ul><p>How about <code>Numeric#step</code>?</p>
<pre><code>>> 0.step.take(3)
=> [0, 1, 2]
>> 1.step.take(3)
=> [1, 2, 3]
</code></pre> Ruby master - Feature #10498: Make `loop` yield a counterhttps://redmine.ruby-lang.org/issues/10498?journal_id=499882014-11-17T13:38:44Ztrans (Thomas Sawyer)
<ul></ul><p>I always thought it would be most convenient if all loops had an intrinsic counter <code>$i</code>.</p> Ruby master - Feature #10498: Make `loop` yield a counterhttps://redmine.ruby-lang.org/issues/10498?journal_id=499912014-11-17T20:44:22Zrklemme (Robert Klemme)shortcutter@googlemail.com
<ul></ul><p>I am actually against this feature. Reason: an infinite loop does not need a counter. We incur the cost of counting (especially when the figure leaves Fixnum space) on <em>all</em> infinite loops. For loops that have a fixed condition on the number (some have been shown with step take or other) that condition can be used upfront with a range or #step.</p>
<p>One can create a counting infinite loop like this:</p>
<pre><code>x = Enumerator::Generator.new {|y| i = 0; loop {y << i; i += 1}}
</code></pre>
<p>or even</p>
<pre><code>x = Enumerator::Generator.new {|y| i = -1; loop {y << (i += 1)}}
</code></pre>
<p>If needed that can be made a constant somewhere, e.g. in Enumerator.</p> Ruby master - Feature #10498: Make `loop` yield a counterhttps://redmine.ruby-lang.org/issues/10498?journal_id=500002014-11-18T14:31:26Zcesario (Franck Verrot)franck@verrot.fr
<ul></ul><p>Hi Robert, thanks for taking time reading the ticket.</p>
<p>Robert Klemme wrote:</p>
<blockquote>
<p>I am actually against this feature. Reason: an infinite loop does not need a counter.</p>
</blockquote>
<p>Most examples I can find about it (and use personally when teaching) make use of a counter (all languages). Keeping track of the current iteration can be useful.</p>
<blockquote>
<p>We incur the cost of counting (especially when the figure leaves Fixnum space) on all infinite loops.</p>
</blockquote>
<p>I definitely agree . I wasn't able to find a way to fine-tune this based on the block's arity as mentioned previously.<br>
On the other hand, you'd need 4,611,686,018,427,387,903 iterations before paying the price of using <code>BigNum</code>s, which compared to the code you're having in the block would probably be more expensive than incrementing a <code>BigNum</code>.<br>
So I'm not sure whether or not that price should be considered high. Anything I'm missing?</p>
<blockquote>
<pre><code>x = Enumerator::Generator.new {|y| i = -1; loop {y << (i += 1)}}
</code></pre>
<p>If needed that can be made a constant somewhere, e.g. in Enumerator.</p>
</blockquote>
<p>Given the context, I'm afraid I wouldn't use this unless it's a well-known constant.</p>
<p>Thanks again, looking forward to more insights :-)</p> Ruby master - Feature #10498: Make `loop` yield a counterhttps://redmine.ruby-lang.org/issues/10498?journal_id=500012014-11-18T14:47:32Zrklemme (Robert Klemme)shortcutter@googlemail.com
<ul></ul><p>Franck Verrot wrote:</p>
<blockquote>
<p>Hi Robert, thanks for taking time reading the ticket.</p>
</blockquote>
<p>You're welcome!</p>
<blockquote>
<p>Robert Klemme wrote:</p>
<blockquote>
<p>I am actually against this feature. Reason: an infinite loop does not need a counter.</p>
</blockquote>
<p>Most examples I can find about it (and use personally when teaching) make use of a counter (all languages). Keeping track of the current iteration can be useful.</p>
</blockquote>
<p>"can"!</p>
<blockquote>
<blockquote>
<p>We incur the cost of counting (especially when the figure leaves Fixnum space) on all infinite loops.</p>
</blockquote>
<p>I definitely agree . I wasn't able to find a way to fine-tune this based on the block's arity as mentioned previously.</p>
</blockquote>
<p>That seems fairly easy:</p>
<pre><code>def lp(&b)
return to_enum(:lp) unless b
if b.arity == 0
while true
b[]
end
else
i = 0
while true
b[i]
i += 1
end
end
raise "This must never happen"
end
</code></pre>
<blockquote>
<p>On the other hand, you'd need 4,611,686,018,427,387,903 iterations before paying the price of using <code>BigNum</code>s, which compared to the code you're having in the block would probably be more expensive than incrementing a <code>BigNum</code>.</p>
</blockquote>
<p>Yes, but as a user of loop you would not have a choice any more. I'd rather use the approach from above or define another method loop_with_index or use the approach with Generator and a constant. I would definitively not unconditionally provide a counter.</p>
<blockquote>
<p>So I'm not sure whether or not that price should be considered high. Anything I'm missing?</p>
</blockquote>
<p>I think it is generally bad to do unnecessary work. Also it is inelegant. :-)</p> Ruby master - Feature #10498: Make `loop` yield a counterhttps://redmine.ruby-lang.org/issues/10498?journal_id=500032014-11-18T16:24:39Zcesario (Franck Verrot)franck@verrot.fr
<ul></ul><p>Robert Klemme wrote:</p>
<blockquote>
<blockquote>
<p>[...] I wasn't able to find a way to fine-tune this based on the block's arity as mentioned previously.</p>
</blockquote>
<p>That seems fairly easy:</p>
<pre><code>def lp(&b)
return to_enum(:lp) unless b
if b.arity == 0
while true
b[]
end
else
i = 0
while true
b[i]
i += 1
end
end
raise "This must never happen"
end
</code></pre>
</blockquote>
<p>I meant in C but yes, given we could have <code>Kernel#loop_with_index</code> implemented in Ruby, it would be a no-brainer.</p>
<blockquote>
<blockquote>
<p>On the other hand, you'd need 4,611,686,018,427,387,903 iterations before paying the price of using <code>BigNum</code>s, which compared to the code you're having in the block would probably be more expensive than incrementing a <code>BigNum</code>.</p>
</blockquote>
<p>Yes, but as a user of loop you would not have a choice any more. I'd rather use the approach from above or define another method loop_with_index or use the approach with Generator and a constant. I would definitively not unconditionally provide a counter.</p>
</blockquote>
<p>I get your point.</p>
<p><code>times</code> does yield a counter, would you say it's the same concern?</p> Ruby master - Feature #10498: Make `loop` yield a counterhttps://redmine.ruby-lang.org/issues/10498?journal_id=500042014-11-18T16:33:46Zrklemme (Robert Klemme)shortcutter@googlemail.com
<ul></ul><p>Franck Verrot wrote:</p>
<blockquote>
<p>Robert Klemme wrote:</p>
</blockquote>
<blockquote>
<blockquote>
<p>Yes, but as a user of loop you would not have a choice any more. I'd rather use the approach from above or define another method loop_with_index or use the approach with Generator and a constant. I would definitively not unconditionally provide a counter.</p>
</blockquote>
<p>I get your point.</p>
<p><code>times</code> does yield a counter, would you say it's the same concern?</p>
</blockquote>
<p>No, because that is specifically designed for iterating a fixed number of times.</p> Ruby master - Feature #10498: Make `loop` yield a counterhttps://redmine.ruby-lang.org/issues/10498?journal_id=507192014-12-31T06:29:12Zduerst (Martin Dürst)duerst@it.aoyama.ac.jp
<ul><li><strong>Assignee</strong> changed from <i>core</i> to <i>matz (Yukihiro Matsumoto)</i></li></ul> Ruby master - Feature #10498: Make `loop` yield a counterhttps://redmine.ruby-lang.org/issues/10498?journal_id=693692018-01-05T21:01:30Znaruse (Yui NARUSE)naruse@airemix.jp
<ul><li><strong>Target version</strong> deleted (<del><i>2.2.0</i></del>)</li></ul>