From: Brian Candler Date: 2003-08-08T18:40:38+09:00 Subject: Re: Why does Ruby have callcc? Here's my entry for the 'writing BASIC in Ruby' competition: $lines = {} $running = false $tron = false def line(n,&blk) callcc { |$lines[n]| } puts "Line #{n}" if $tron and $running yield if $running end def goto n $lines[n].call end def run unless $running $running = true $lines.sort[0][1].call $end end line(100) { puts "Hello World" } line(110) { $i = 0 } line(120) { if $i > 10 then goto 160 end } line(130) { puts "Current $i: %d" % [$i] } line(140) { $i = $i + 1 } line(150) { goto 120 } line(160) { puts "Done!" } line(170) { puts "Stopping now" } # $tron = true run One thing worth mentioning about continuations is that as far as I can tell, Continuation#call NEVER RETURNS. You are not pushing the current execution state onto a stack like Method#call or Proc#call; you are simply replacing the current execution context, like a longjmp in C. The current execution thread is lot. In that case perhaps 'call' is not the ideal name for this method. The thing I am not sure of is what values of variables, if any, are bound up in the continuation. Take the following example: i = 0 here = nil callcc {|here|} puts i i = i + 1 here.call unless i == 10 # here.call is just "goto here" puts "Done!" This is not recursive - as mentioned before, here.call just rewinds to the point after the callcc. Now, clearly the *value* of variable 'i' at callcc time is not included in the continuation object 'here', because when I do 'here.call', the subsequent 'puts i' shows 'i' with its new value. I think what confuses me is the discussion on the Wiki about coming to a crossroads, taking the left path, finding that you get bitten by a dog, and then deciding that was a bad idea so you 'rewind back in time' to the crossroads. But if you did this using a Ruby continuation, surely your leg would still be bleeding? preferred_path = "LEFT" bleeding = false crossroads = nil callcc{ |crossroads| } puts "At the crossroads" puts bleeding ? "I am bleeding!" : "I am OK" puts "I am going to go #{preferred_path}" if preferred_path == "LEFT" sleep 2 puts "Bitten by dog!" bleeding = true preferred_path = "RIGHT" crossroads.call else sleep 2 puts "Hit by train!" exit end Regards, Brian.