Issue #10498 has been updated by Robert Klemme.


Franck Verrot wrote:
> Hi Robert, thanks for taking time reading the ticket.

You're welcome!

> Robert Klemme wrote:
> > I am actually against this feature.  Reason: an infinite loop does not need a counter.  
> 
> 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.

"can"!

> > We incur the cost of counting (especially when the figure leaves Fixnum space) on all infinite loops.
> 
> I definitely agree . I wasn't able to find a way to fine-tune this based on the block's arity as mentioned previously.

That seems fairly easy:

~~~
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
~~~

> On the other hand, you'd need 4,611,686,018,427,387,903 iterations before paying the price of using `BigNum`s, which compared to the code you're having in the block would probably be more expensive than incrementing a `BigNum`.

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.

> So I'm not sure whether or not that price should be considered high. Anything I'm missing?

I think it is generally bad to do unnecessary work.  Also it is inelegant. :-)

----------------------------------------
Feature #10498: Make `loop` yield a counter
https://bugs.ruby-lang.org/issues/10498#change-50001

* Author: Franck Verrot
* Status: Open
* Priority: Normal
* Assignee: ruby-core
* Category: core
* Target version: current: 2.2.0
----------------------------------------
# Problem

Teaching Ruby, we always end up with that type of construct

```ruby
i = 0
loop do
  i += 1
  # do something with i....
  raise StopIteration if i ...
end
```

# Solution

What I propose with this patch is making `loop` yield the iteration count:

```ruby
loop do |i|
  # do something with i....
  raise StopIteration if i ...
end
```

`i` starts at 0 and stops at `FIXNUM_MAX` (there's no `Float::Infinity` equivalent for integers).

# Alternate solution

`Integer#times` could work if we had an `<Integer's infinity>` object, so we would just do `<Integer's Infinity>.times { |i| ... }`.

Also, this is the very first patch I submit to Ruby, I might have done something horrible, feel free to tell me :-)

---Files--------------------------------
0001-vm_eval.c-loop-now-yields-a-incremented-counter.patch (1.74 KB)
0001-vm_eval.c-loop-now-yields-a-incremented-counter.patch (1.86 KB)


-- 
https://bugs.ruby-lang.org/