views:

88

answers:

2

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.

+3  A: 

Yeah, nil is still a result, which is different than not having a value to return. It's basically the same as trying to access a variable or a location in memory that's not there. This is why you want an exception rather than returning a nil. Sounds like you figured that out :-)

Jon Smock
+4  A: 

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.

mikej
OCaml goes even further - the more-or-less-equivalent of Ruby's `hash[key]` (`List.assoc key hash`) raises an exception (`Not_found`) if the key is not represented. It's actually quite logical - the "normal" thing you expect when you call `:next` is to get the next value. *Not* getting the next value is clearly then an exceptional situation.
Amadan
@Amadan: `hash.fetch(key)` will raise a `KeyError` if key is not found.
Marc-André Lafortune
Interesting argument Amadan - I buy it.
Asher