Once again I’ve been trying to get a grip on continuations, however, I’m
quite unsure whether I’ve really got it this time. Could anybody please
take a look at the example ‘server’ below. It seems to work when called
from irb, but I’m unclear on how to test such a beast programmatically,
so I suspect I somehow must have got it wrong again.
TIA,
Patrick
class ContServer
def initialize()
@blocks={} # named services
@mains={} # top-level continuations by session id
@conts={} # service continuations by session id
end
def add(name,&block)
@blocks[name]=block
end
def service(id,name=’’,inp=’’)
callcc do |cc|
@mains[id]=cc # remember top-level continuation
if(@conts.key?(id)) # already in session?
@conts[id].call(inp) # return to service continuation
else
ret=@blocks[name].call(id,self) # enter new session
@conts.delete(id) # finish session
ret
end
end
end
def io(id,out)
callcc do |cc|
@conts[id]=cc # remember service continuation
@mains[id].call(out) # return to top-level continuation
end
end
def ContServer::init
cs=ContServer.new
cs.add(‘guess’) do |id,server|
target=rand(100)
inp=server.io(id,“Please enter a number between 1 and 100.”).to_i
round=1
while(inp!=target)
inp=server.io(id,(inp < target ? “Higher” : “Lower”)).to_i
round += 1
end
"You found it in #{round} rounds."
end
cs
end
end
–snip–code
How are you calling it from IRB? It didn’t work for me, and before I
spent too much time trying to figure out why, I thought I’d ask this
first.
Chad
···
On 11/4/2004, at 6:44 AM, Patrick Roemer wrote:
Once again I’ve been trying to get a grip on continuations, however,
I’m
quite unsure whether I’ve really got it this time. Could anybody please
take a look at the example ‘server’ below. It seems to work when called
from irb, but I’m unclear on how to test such a beast programmatically,
so I suspect I somehow must have got it wrong again.
TIA,
Patrick
Hi,
Once again I’ve been trying to get a grip on continuations, however, I’m
quite unsure whether I’ve really got it this time. Could anybody please
take a look at the example ‘server’ below. It seems to work when called
from irb, but I’m unclear on how to test such a beast programmatically,
so I suspect I somehow must have got it wrong again.
This looks very solid to me. Maybe you could make every
Service a subclass of ContSession, and every session an
instance of that session. It would look something like this:
class ContSession
def start(*args)
callcc do |cc|
@main = cc
session(*args)
end
end
def service(arg)
callcc do |cc|
@main = cc
@cont.call(arg)
end
end
def io(out)
callcc do |cc|
@cont = cc
@main.call(out)
end
end
private :io
end
class Guess < ContSession
def session
target = rand(100)
inp = io(“Please enter a number between 1 and 100.”).to_i
round = 1
while(inp != target)
inp = io(inp < target ? “Higher” : “Lower”).to_i
round += 1
end
“You found it in #{round} rounds.”
end
private :session
end
irb(main):002:0> g = Guess.new
#Guess:0x402a7484
irb(main):003:0> g.start
“Please enter a number between 1 and 100.”
irb(main):004:0> g.service(50)
“Lower”
irb(main):005:0> g.service(25)
“Higher”
irb(main):006:0> g.service(37)
“Lower”
irb(main):007:0> g.service(31)
“Higher”
irb(main):008:0> g.service(34)
“You found it in 5 rounds.”
···
On Sun, 11 Apr 2004 12:41:50 +0200, Patrick Roemer wrote:
Hi,
Once again I’ve been trying to get a grip on continuations, however, I’m
quite unsure whether I’ve really got it this time. Could anybody please
take a look at the example ‘server’ below. It seems to work when called
from irb, but I’m unclear on how to test such a beast programmatically,
so I suspect I somehow must have got it wrong again.
It looks very solid to me. Maybe you could make every Service a
subclass of ContSession, and every session an instance of that Session.
It would look something like this:
class ContSession
def start(*args)
callcc do |cc|
@main = cc
session(*args)
end
end
def service(arg)
callcc do |cc|
@main = cc
@cont.call(arg)
end
end
def io(out)
callcc do |cc|
@cont = cc
@main.call(out)
end
end
private :io
end
class Guess < ContSession
def session
target = rand(100)
inp = io(“Please enter a number between 1 and 100.”).to_i
round = 1
while(inp != target)
inp = io(inp < target ? “Higher” : “Lower”).to_i
round += 1
end
“You found it in #{round} rounds.”
end
private :session
end
irb(main):002:0> g = Guess.new
#Guess:0x402a7484
irb(main):003:0> g.start
“Please enter a number between 1 and 100.”
irb(main):004:0> g.service(50)
“Higher”
irb(main):005:0> g.service(75)
“Higher”
irb(main):006:0> g.service(81)
“Higher”
irb(main):007:0> g.service(90)
“Higher”
irb(main):008:0> g.service(95)
“Lower”
irb(main):009:0> g.service(93)
“Lower”
irb(main):010:0> g.service(91)
“You found it in 7 rounds.”
irb(main):011:0>
···
On Sun, 11 Apr 2004 12:41:50 +0200, Patrick Roemer wrote:
Patrick Roemer wrote:
Once again I’ve been trying to get a grip on continuations, however, I’m
Your code looks solid and as though you have been trough with the
concept. Might I suggest the source code of Borges for further reading
on this subject ?
(I guess you know Seaside and/or other Continuation based web
programming frameworks, there seems to be a bit of talk about that lately).
kaspar - code philosopher
- – stolen off the net –
So much for taking the world by storm. I guess I’ll have to take it by
siege.
– Jay J. P. Scott
Chad Fowler wrote:
How are you calling it from IRB? It didn’t work for me, and before I
spent too much time trying to figure out why, I thought I’d ask this
first.
Thanks for your reply. I have to admit that ‘calling from irb’ is not a
very detailed description. I meant something like this:
irb(main):001:0> require ‘conttest.rb’
=> true
irb(main):002:0> cs=ContServer.init
=> #<ContServer:0x2812560 @conts={},
@mains={}, @blocks={“guess”=>#Proc:0x02812548@./conttest.rb:34}>
irb(main):003:0> cs.service(1,‘guess’,50) # (last arg ignored)
=> “Please enter a number between 1 and 100.”
irb(main):004:0> cs.service(1,‘guess’,50) # (middle arg ignored)
=> “Lower”
irb(main):005:0> cs.service(1,‘guess’,25) # (middle arg ignored)
=> “You found it in 2 rounds.”
irb(main):006:0> cs.service(1,‘guess’,25) # (last arg ignored)
=> “Please enter a number between 1 and 100.”
irb(main):007:0> cs.service(1,‘guess’,50) # (middle arg ignored)
=> “Higher”
…and so on. This also seems to work with multiple ‘services’ and
multiple ‘users’ (i.e. IDs) with interleaved access.
Please try to ignore the crappy arg handling (and also the off-by-one
error for the random expectation). I’m just trying to figure out how a
continuation-based web server is supposed to work. For me this was the
‘simplest thing that could possibly emulate this’. Perhaps I am totally
off the track, but if so, I’d really like to know why.
Regards,
Patrick
Kristof Bastiaensen wrote:
It looks very solid to me.
In the meantime I’ve found out that the problem was not in the code I
posted, but in my test.
Your version looks really nice. I think it could fit nicely with the
other continuation examples in the Ruby FAQ. Thanks.
Regards,
Patrick
Kaspar Schiess wrote:
Your code looks solid and as though you have been trough with the
concept. Might I suggest the source code of Borges for further reading
on this subject ?
Good idea, I hadn’t discovered Borges yet.
(I guess you know Seaside and/or other Continuation based web
programming frameworks, there seems to be a bit of talk about that lately).
I’ve found continuations in Cocoon’s flow script (i.e. in Cocoon’s
Javascript/Rhino extension), but before using it, I wanted to get a grip
on the basic concept and I felt more comfortable experimenting with it
in Ruby rather than Javascript or Scheme. Now that I seem to have got
it, I’ll have a look at Borges to see it in action. Thanks for the hint.
Regards,
Patrick
I’ve also written a tiny bit of code to attempt to educate myself and
others on how Seaside-like frameworks work. I plan to eventually
implement all of the “tricks” that Seaside employs in as little code as
possible (with the goal being clarity–not brevity). Right now I just
have the first trick implemented. The code is really stupid, but
that’s beside the point.
http://chadfowler.com/lazyseaside/pm_seaside.html
Ignore the “seasidehints.out” and “wrap_methods” stuff. That’s
unrelated and part of another idea I was exploring
(http://chadfowler.com/index.cgi/Computing/Programming/Ruby/
TypeWatching.rdoc,v).
Chad
···
On 12/4/2004, at 7:39 AM, Patrick Roemer wrote:
I’ve found continuations in Cocoon’s flow script (i.e. in Cocoon’s
Javascript/Rhino extension), but before using it, I wanted to get a
grip
on the basic concept and I felt more comfortable experimenting with it
in Ruby rather than Javascript or Scheme. Now that I seem to have got
it, I’ll have a look at Borges to see it in action. Thanks for the
hint.
I’ve found continuations in Cocoon’s flow script (i.e. in Cocoon’s
Javascript/Rhino extension), but before using it, I wanted to get a grip
on the basic concept and I felt more comfortable experimenting with it
in Ruby rather than Javascript or Scheme. Now that I seem to have got
it, I’ll have a look at Borges to see it in action. Thanks for the hint.
Have a look at Borges then, it does what you want and ten times more: It
rocks ! (Having come the same way from Cocoon… )
kaspar - code philosopher
- – stolen off the net –
“It takes real courage to be a Macintosh user; it takes real conviction;
~ not unlike being a Christian in the days of the Romans.”
~ - Guy Kawasaki, Chief Evangelist for Apple Computer - from “Hotseat”
~ interview with John McChesney (3/28/97)
Thanks!
Maybe you are interested in the following code (if it
doesn’t exist already). In implements a kind of goto:
class Mark
def initialize
@cc = callcc { |cc| cc }
end
def goto #should be called teleport
@cc.call(@cc)
end
end
#-- (the example is quite stupid, but just to show the concept)
irb(main):006:0> begin
irb(main):007:1* a = Mark.new
irb(main):008:1> a.goto if gets.chomp != “stop”
irb(main):009:1> end
Hi, there
Everything ok!
stop
nil
irb(main):010:0>
···
On Mon, 12 Apr 2004 13:36:13 +0200, Patrick Roemer wrote:
Your version looks really nice. I think it could fit nicely with the
other continuation examples in the Ruby FAQ. Thanks.
#----