Issue #7696 has been updated by shugo (Shugo Maeda).


marcandre (Marc-Andre Lafortune) wrote:
> The same idea will work for zip too; the arguments must be converted to enumerators only when yielder.memo is not set, i.e. every new yielder.
> 
> The arguments are never really rewound, but the first yielder holding them will not be reused after enum.rewind; a new yielder is given.
> I haven't checked if that's the current behavior in other implementations, but if yielder is to be the state holder, that's the way it should work.

So, the following behavior is intended, right?

  $ ruby1.9.3 -I ~/src/backports/lib  -r backports -r backports/2.0.0/enumerable -e "a = (1..3).lazy.zip(('a'..'z').each); p a.to_a; p a.to_a"
  [[1, "a"], [2, "b"], [3, "c"]]
  [[1, "d"], [2, "e"], [3, "f"]]

> So, does the patch look acceptable as far as MRI is concerned?

If the above behavior is intended, the patch looks acceptable.

> For the public api, should there be a public Yielder#memo and a guarantee that there is exactly one yielder object per iteration? or instead an extra state yielded when required?

It might be too late to introduce a new API for 2.0.0, so how about to move it to next minor?


----------------------------------------
Bug #7696: Lazy enumerators with state can't be rewound
https://bugs.ruby-lang.org/issues/7696#change-35511

Author: marcandre (Marc-Andre Lafortune)
Status: Open
Priority: High
Assignee: 
Category: core
Target version: 2.0.0
ruby -v: r38800


The 4 lazy enumerators requiring internal state, i.e. {take|drop}{_while}, don't work as expected after a couple `next` and a call to `rewind`.

For example:

    e=(1..42).lazy.take(2)
    e.next # => 1
    e.next # => 2
    e.rewind
    e.next # => 1
    e.next # => StopIteration: iteration reached an end, expected 2

This is related to #7691; the current API does not give an easy way to handle state.

Either there's a dedicated callback to rewind, or data must be attached to the yielder.


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