Jacob Fugal wrote:
> On 2/12/06, Luke Blanshard <luke / blanshard.us> wrote:
>   
>>     x = 1
>>     g = Generator.new do |g|
>>       5.times {|i| g.yield [x,i].max}
>>     end
>>
>>     until g.end?
>>       x = 10 if g.current > 2
>>       puts g.next
>>     end
>>
>> This outputs 1, 1, 2, 3, 10.
>>
>> The next question is, why is the API for this class so crappy?  I would
>> have expected the output to be 1, 1, 2, 10, 10.  But creating the
>> generator automatically advances to the first yield, and "next" advances
>> to the next one while returning the previous one.  This is just wrong.
>>     
>
> Actually, there's no way (I can think of) to get the output you
> expect, and it has nothing to do with an initial advance or anything.
> My implementation doesn't advance to the yields until required, yet
> has the same output. This is because of these two lines:
>
>  x = 10 if g.current > 2
>  puts g.next
>
> g.current returns the current value. g.current is not greater than two
> until g.current == 3. g.next then returns the same as g.current, while
> also advancing the internal counter. The behavior your describing
> would require changing the value of g.current by assigning to x. Can't
> be done.
>   

You are correct.  My bad.

My point is that the API is pointlessly difficult.  I think, actually, 
that the C# iterator API is the cleanest I've seen: there is one 
operation that attempts to advance to the next position, returning false 
if it has reached the end, and another that returns the current value, 
throwing an exception if it's still before the first advance.

And my other point is that, while you're going down the road of 
coroutines, you might as well go the whole way.

Luke Blanshard