Ruby Enumerator - Why Finish with Exception?
Asked Answered
N

2

7

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.

Napper answered 9/7, 2010 at 12:27 Comment(1)
Just want to point out that #loop catches this exception, so loop { enumerator.next } eliminates the need to explicitly handle it.Vasya
F
7

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.

Fideicommissary answered 9/7, 2010 at 15:39 Comment(3)
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.Contemptuous
@Amadan: hash.fetch(key) will raise a KeyError if key is not found.Helldiver
Interesting argument Amadan - I buy it.Napper
S
4

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 :-)

Stradivarius answered 9/7, 2010 at 12:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.