----- Original Message -----
From: Brian Candler <B.Candler / pobox.com>
Date: Friday, August 8, 2003 5:40 am
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 
> executionstate onto a stack like Method#call or Proc#call; you are 
> simply replacing
> the current execution context, like a longjmp in C. The current 
> executionthread 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
> 

As I understand it, continuations are, in a way, a
superset of closures. A continuation creates a
closure that also has information on where it was
executing at the time, so when you execute the
continuation, it goes back to that place, in addition
to having the appropriate context. Closures don't
simply make a copy of the stack and restore it, it's
more like they make a reference to a persistant
lexical storage area (read about closures on Dan's
blog about parrot for a better explanation of this).
So for example:

def foo
   x = 5
   q = proc { x }
   x = 3
end

fun = foo
puts fun[]

Would, I think print 3, rather than 5, since q
would store a reference to the lexical context of
that call to foo, rather than just making a copy of
the stack up to when proc was called. Likewise,
callcc would make a reference to that lexical
scratch-pad, and values wouldn't be replaced with
their previous values by resuming the continuation.

I think this makes callcc a bit different than
setjmp and longjmp from C (although I haven't used
them, only read about them), as I believe they make
a copy of, and restore the stack.

Note, though, that I could be way off base, since
I'm not able to test the closure example right now.
It's based on my understanding of them, though.

You should be able to implement closures with
continuations, though, and if continuations changed
the values back to what were when the continuation
was taken, then you couldn't implement something
like:

def foo
   x = 1
   return proc { x += 1; x }
end

With continuations without some major headaches, I think.

Hope this all makes sense.

- Dan