Bug #10534
closedEnumerator methods other than "next" do not always respect "peek"
Description
It seems like using "peek" and then calling other methods on the Enumerator consumes the value that was peeked at. While next
correctly returns the peeked-at value the next time it is called, other Enumerator methods such as to_a
and each
do not.
>> enum = StringIO.new("foo").each
=> #<Enumerator: #<StringIO:0x007ff3313d8688>:each>
>> enum.peek
=> "foo"
>> enum.to_a
=> []
Here the final call to enum.to_a
should have returned ["foo"]
, since we have not consumed anything from the enumerator yet. The peeked-at value is not included in the returned Array.
Taking a glance at the code, it seems that these methods do not call next
under the hood, but instead have some other mechanism of iterating over the Enumerator, this seems very counter-intuitive to me.
Updated by marcandre (Marc-Andre Lafortune) over 9 years ago
- Assignee deleted (
matz (Yukihiro Matsumoto))
next
and peek
indeed live in their little world described as "external enumeration" in the documentation.
The documentation of next
and next_values
states:
- Note that +next_values+ does not affect other non-external enumeration
- methods unless underlying iteration method itself has side-effect, e.g.
- IO#each_line.
The doc of peek
and peek_values
would benefit from a similar note. Maybe we should turn it around in this case, like:
- Note that +peek+ will affect other non-external enumeration
- methods if underlying iteration method itself has side-effect, e.g.
- IO#each_line.
Updated by bmesuere (Bart Mesuere) almost 9 years ago
- Subject changed from Enumerator methods other than "next" do not respect "peek" to Enumerator methods other than "next" do not always respect "peek"
I don't agree that a documentation would fix this. This issue results in unpredictable behaviour:
$ ruby -e "e=['a','b','c'].each;puts e.peek;puts e.next"
a
a
$ ruby -e "e=['a','b','c'].each;puts e.peek;e.each{|l| puts l}"
a
a
b
c
$ echo -e "a\nb\nc" | ruby -e "e=STDIN.each_line;puts e.peek;puts e.next"
a
a
$ echo -e "a\nb\nc" | ruby -e "e=STDIN.each_line;puts e.peek;e.each{|l| puts l}"
a
b
c
There's no way to know if the underlying iteration method has "side effects" except from trying it.
Updated by jeremyevans0 (Jeremy Evans) over 3 years ago
- Status changed from Open to Rejected