Search code examples
rubyexceptionenumerator

Ruby Enumerator - Why Finish with Exception?


Iterating a block in Ruby is simple enough - it finishes cleanly and proceeds on to the rest of the code.

Iterating with an Enumerator, on the other hand, is a bit more confusing. If you call :each without a block, an Enumerator is returned instead. :next can then be called on the Enumerator to get each next iterative value.

And then the odd part- when iteration is complete, instead of the Enumerator returning nil, it throws an exception: "iteration reached at end". The result is that it doesn't even return a value.

For instance:

test = [ 'test_value' ]
enumerator = test.each
enumerator.next
>> "test_value"
enumerator.next
>> StopIteration: iteration reached at end

Is the reason for this simply so that nil values can be returned by the Enumerator? The answer occurs to me only as I post this (so I am going to post it still), but seems like it must be the case.

If that is so, is this a typical way of handling such issues? It seems odd to use an Exception to handle code that essentially performs as expected.


Solution

  • You are correct that the reason is so that nil can be returned as a valid value by the Enumerator. To answer your question of whether this is typical, Python handles it in the same way using an exception also called StopIteration.

    >>> my_list = [1,2,3]
    >>> i = iter(my_list)
    >>> i.next()
    1
    >>> i.next()
    2
    >>> i.next()
    3
    >>> i.next()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    StopIteration
    

    Of course, most of the time next isn't called directly (each or a for loop being used instead) so this underlying mechanism isn't exposed that often.