Im am preparing a small presentation for ruby. Therefore I was searching for a
continuation example. I tried to make a Java like iterator for any ruby class
with an each() method. This is the solution I found:
What do you think of this approach? Is there an easier way to do it?
Not a easier way, but, since Ruby’s callcc is kind of slow, I think
it’s better to make a thread and connect with queue. Take a look at: http://www.imasy.or.jp/~fukumoto/ruby/pipe.rb
You should be able to find some approaches in the ruby-talk archives.
There’s also Knu’s implementation in CVS (look in “rough”). If you
have problems finding them I can look for more details.
Regards,
Pit
···
On 17 Mar 2003 at 3:29, Hans Jörg Hessmann wrote:
Im am preparing a small presentation for ruby. Therefore I was searching for a
continuation example. I tried to make a Java like iterator for any ruby class
with an each() method. This is the solution I found:
class Iterator
(…)
What do you think of this approach? Is there an easier way to do it?
This looks like a reasonable approach, particularly for an example.
Some comments:
What happens if @enum.each raises an exception? (I think that it
will appear that the exception is coming from #initialize rather
than #next, which might not be the desired behavior).
This approach to iterating is very slow. It’s better to make a few
iterations at a time, so you don’t have to call @next every time
you want a new element.
See [ruby-talk:35757] and the following thread for lots of links to
other people who have implemented this style of iterator in Ruby.
Paul
···
On Mon, Mar 17, 2003 at 03:29:28AM +0900, Hans Jörg Hessmann wrote:
What do you think of this approach? Is there an easier way to do it?
What happens if @enum.each raises an exception? (I think that it
will appear that the exception is coming from #initialize rather
than #next, which might not be the desired behavior).
This approach to iterating is very slow. It’s better to make a few
iterations at a time, so you don’t have to call @next every time
you want a new element.
See [ruby-talk:35757] and the following thread for lots of links to
other people who have implemented this style of iterator in Ruby.
Well, I thought it was a good solution that shows an extraordinary
ruby-feature. But I didn’t check the performance. It’s really too slow for
real-world applications.
It looks like there is no better solution than using some sort of pipe.
Anyway, Gavin is right: continuations are nothing for a ruby intoduction. But
I stumbled over this problem during my preparation and it made me curious.
It least I’ve learned something and it was a bit of fun.
This looks like a reasonable approach, particularly for an example.
I think so too, and add more comments:
If the enumerable object has nil, hasNext returns false.
It will stop the loop.
ex) iter = Iterator.new([1, nil, 5])
while iter.hasNext? #=> stops at nil
puts iter.next
end
The symmetry of @back and @next is ignored.
The following is a little improvement of the original code:
class Iterator
def initialize(enum) @next = nil @back = nil
enum.each do |el|
@current = el
callcc do |cc|
@next = cc
if @back then @back.call else return end
end
end
@next = nil
@back.call if @back
end
def hasNext? @next
end
def next
last = @current
callcc do |cc| @back = cc @next.call if @next
end
last
end
end
As others said, the library using callcc is not a tool for real
applications. But it attracts theoritical interest. I collected
the very short codes for Continuation:
It includes the generic library CoThread. Using this, the iterator
can be written as follows:
require “co-thread”
class Iterator
def initialize(enum) @ct = CoThread.new @ct.fork do
prev = nil @more = true
enum.each do |x| @ct.pass(prev)
prev = x
end @more = false @ct.pass(prev)
end @ct.pass
end