Why does Ruby have callcc?

As for why callcc takes a block (I didn’t see this in any of the replies
so far)…

If you look at Scheme’s call-with-current-continuation, it’s syntax:

(callcc f)

Where f is the function you want called. callcc then calls:

(f cc)

Where cc is the continuation, so you’d often see something like:

(callcc (lambda (cc) (my-fun cc arg1 arg2 ...))

Which makes an anonymous function that accepts the continuation and
passes it, along with some other arguments, on to another function that
does stuff.

Now, to do this in ruby (most easily), you’d do:

callcc { |cc|
my_fun cc, arg1, arg2 …
}

Since blocks are similar to lambda constructs. The other option would
be to use actual methods for callcc, but then you’d be creating all
kinds of one-argument methods just to call other methods, and that’s
really the job of a block or a Proc.

And if you want to see something that you need callcc to do, you can
search the mailing list for Callcc and insomnia (or something like
that), where I was experimenting with them and made, more or less, a
class that mimics Python’s generators (or what Parrot calls coroutines)
with them. That’s not exactly a practical application (although I do use
them in the code for my web page), since it’s essentially implementing
more language functionality that you may or may not use, but I find that
sort of thing interesting, at least.

Cheers.

  • Dan

Where cc is the continuation, so you’d often see something like:

(callcc (lambda (cc) (my-fun cc arg1 arg2 …))

Ok, and the reason you need to have this lambda is that callcc is a
function that takes one argument: a function which itself takes one
argument, the CC. Because my-fun requries more than one argument, you
need the lambda, right?

Which makes an anonymous function that accepts the continuation and
passes it, along with some other arguments, on to another function
that does stuff.

Now, to do this in ruby (most easily), you’d do:

callcc { |cc|
my_fun cc, arg1, arg2 …
}

So it looks like Ruby is trying to look like the scheme implementation.
Sometimes trying to mimic the way things look in a functional language
when programming in an imperative language makes for convoluted code.
There may be some subtlety I’m missing, but it seems like you aught to
be able to have a “returncc” function in scheme that takes no arguments
and returns a continuation context thingo, then use it like:

(my_fun (returncc) arg1 arg2 arg3 …)

It could probably even be implemented as

(lambda (cc) cc)

Though, my scheme is weak to nonexistent so I’m not 100% sure I have
the syntax right.

I’m just not sure exactly where things end up if you call that
continuation context… though I suppose you’d just end up right in the
middle of assigning arguments to a method call, followed by actually
calling the method.

If that’s possible, this should work in Ruby:

my_fun(Continuation.new, arg1, arg2, arg3, …)

Or, more clear to me:

cc = Continuation.new
my_fun(cc, arg1, arg2, arg3, …)

Am I out to lunch, or does any of this make sense?

Ben

···

On Wednesday, August 6, 2003, at 08:32 PM, Dan Doel wrote:

Actually, no. One of the useful things to do with continuations is to
stash them away for later execution. If cc is the continuation of
“Continuation.new”, then the continuation has already been executed by
the time you get access to it. The block approach does not have this
problem.

Another useful thing is to pass a function’s own continuation to itself
(allowing it to decide how and when to terminate). This looks difficult
to do using the Continuation.new.

Here’s a simple example. Suppose you had a function f that took two
arguments. The first argument is a continuation for normal returns.
The second is a continuation for failure. The function might look like
this (in part)…

def f(normal, abort)
# calculations go here
abort.call if failure
normal.call(return_value)
end

Now we can arrange for the function to abort in different ways. Here’s
how we would call it if we want it to abort by returning nil …

callcc { |normal|
callcc { |abort| f(normal, abort) }
nil
}

Here’s how we call it if we want it to raise an exception when it aborts

callcc { |normal|
callcc { |abort| f(normal, abort) |
raise “Oops”
}

How would you do the same thing with Continuation.new ?

···

On Thu, 2003-08-07 at 00:42, Ben Giddings wrote:

If that’s possible, this should work in Ruby:

my_fun(Continuation.new, arg1, arg2, arg3, …)

Or, more clear to me:

cc = Continuation.new
my_fun(cc, arg1, arg2, arg3, …)

Am I out to lunch, or does any of this make sense?


– Jim Weirich jweirich@one.net http://onestepback.org

“Beware of bugs in the above code; I have only proved it correct,
not tried it.” – Donald Knuth (in a memo to Peter van Emde Boas)

Actually, no. One of the useful things to do with continuations is to
stash them away for later execution. If cc is the continuation of
“Continuation.new”, then the continuation has already been executed by
the time you get access to it. The block approach does not have this
problem.

Continuation.new was meant as a replacement of callcc. The continuation would
still be executed by Continuation#call, which in my mind, would bring you
back to the point immediately after Continuation.new had returned.

How would you do the same thing with Continuation.new ?

Well, in this case, maybe with Continuation.new acting exactly like callcc
does now. I just think it would look a little cleaner than it does now.
“callcc” seems deceptive because you’re not actually calling the
continuation, you’re evaluating a block and passing it the continuation,
which it may call later. I think this syntax:

Continuation.new { |normal_cc|
Continuation.new { |abort_cc| f(normal_cc, abort_cc) }
nil
}

Makes it more clear that the continuation is being created there, but called
later.

The reason I like the idea of a no-block form of Continuation.new is that it
would make this:

arr = [ “Freddie”, “Herbie”, “Ron”, “Max”, “Ringo” ]
callcc{|$cc|}
puts(message = arr.shift)
$cc.call unless message =~ /Max/

Freddie
Herbie
Ron
Max

Much more clear:

arr = [ “Freddie”, “Herbie”, “Ron”, “Max”, “Ringo” ]
cc = Continuation.new
puts(message = arr.shift)
cc.call unless message =~ /Max/

Freddie
Herbie
Ron
Max

In my mental image of how Continuation.new would work, if a block is given,
Continuation#call resumes at the end of the block, just like it does now, but
if no block is given, it would resume right at the point where the
constructor returns, and the value is assigned to cc.

The only thing this doesn’t address is the idea of callcc returning the value
given by Continuation#call. This might mean that Continuation.new isn’t the
right syntax for the block version. Something like Continuation.run or
Continuation.run_block might be more appropriate for that version.

Here’s one that seems to work for me:

class Continuation
def self.new
cc = nil
callcc {|cc| return cc}
cc
end

def self.run
callcc {|cc| yield(c) }
end
end

irb(main):028:0> def countToFive
n=0
cc = Continuation.new
print "#{n} => "; n += 1; puts n
if 5 != n then cc.call end
n
end
=> nil
irb(main):029:0> countToFive
0 => 1
1 => 2
2 => 3
3 => 4
4 => 5
=> 5
irb(main):030:0> Continuation.run {|cont| cont.call(5, 5) }
=> [5, 5]

···

On Thu August 7 2003 3:03 am, Jim Weirich wrote:

How would you do the same thing with Continuation.new ?

Well, in this case, maybe with Continuation.new acting exactly like callcc
does now. I just think it would look a little cleaner than it does now.
“callcc” seems deceptive because you’re not actually calling the
continuation, you’re evaluating a block and passing it the continuation,
which it may call later. I think this syntax:

Continuation.new { |normal_cc|
Continuation.new { |abort_cc| f(normal_cc, abort_cc) }
nil
}

Makes it more clear that the continuation is being created there, but called
later.

The reason I like the idea of a no-block form of Continuation.new is that it
would make this:

arr = [ “Freddie”, “Herbie”, “Ron”, “Max”, “Ringo” ]
callcc{|$cc|}
puts(message = arr.shift)
$cc.call unless message =~ /Max/

Freddie
Herbie
Ron
Max

Much more clear:

arr = [ “Freddie”, “Herbie”, “Ron”, “Max”, “Ringo” ]
cc = Continuation.new
puts(message = arr.shift)
cc.call unless message =~ /Max/

Freddie
Herbie
Ron
Max

In my mental image of how Continuation.new would work, if a block is given,
Continuation#call resumes at the end of the block, just like it does now, but
if no block is given, it would resume right at the point where the
constructor returns, and the value is assigned to cc.

The only thing this doesn’t address is the idea of callcc returning the value
given by Continuation#call. This might mean that Continuation.new isn’t the
right syntax for the block version. Something like Continuation.run or
Continuation.run_block might be more appropriate for that version.

Here’s one that seems to work for me:

class Continuation
def self.new
cc = nil
callcc {|cc| return cc}
cc
end

def self.run
callcc {|cc| yield(c) }
end
end

This works, but only because you’re implementing both with callcc. If
continuations were implemented so that the only way to create one were
Continuation.new, then there would effectively be no way to implement
Continuation.run, because doing:

cc = Continuation.new

cc.call(a, b, c)

would have no way of getting a, b, and c back to where Continuation.new
was called (because it doesn’t make sense for Continuation.new to return
anything but a Continuation object).

The only way to implement callcc using Continuation.new (or something
like it) would be to have a method that captures the enclosing
function’s continuation, so that calling the continuation would return
from the function in which Continuation.new was called. This
essentially comes down to having two methods written in C instead of 1.

I guess the bottom line is, you still need callcc (or something like
it), even if you have Continuation.new. You can write Continuation.new
using callcc, but you can’t write callcc using Continuation.new (without
having some magic stuff happen). callcc is more general.

However, you can, of course, write a little extention that adds the
Continuation.new and Continuation.run methods for your own use, if you
find those more clear than callcc, which is a nice feature of Ruby.

Ahh, that’s where the confusion is! Callcc doesn’t stand for “call
continuation”. It is short for “call with current continuation”. In
other words, it calls a function passing in the current continuation.

Actually, to me it seems that the Continuation.new syntax is the one
that is deceptive. For callcc doesn’t create a NEW continuation, it
just makes the existing continuation for the block available. All
function calls have a continuation (its the code that is executed when
the function returns). Callcc just makes that already existing
continuation available.

···

On Thu, 2003-08-07 at 22:04, Ben Giddings wrote:

Well, in this case, maybe with Continuation.new acting exactly like callcc
does now. I just think it would look a little cleaner than it does now.
“callcc” seems deceptive because you’re not actually calling the
continuation, you’re evaluating a block and passing it the continuation,
which it may call later.


– Jim Weirich jweirich@one.net http://onestepback.org

“Beware of bugs in the above code; I have only proved it correct,
not tried it.” – Donald Knuth (in a memo to Peter van Emde Boas)

This works, but only because you’re implementing both with callcc.

Well… considering that at the moment there isn’t any other way to create a
continuation, I didn’t have all that much choice. :wink:

cc = Continuation.new

cc.call(a, b, c)

would have no way of getting a, b, and c back to where Continuation.new
was called (because it doesn’t make sense for Continuation.new to return
anything but a Continuation object).

Righto. Hence my idea there should be a Continuation.run (though I’m still
not sure I like that name)

I guess the bottom line is, you still need callcc (or something like
it), even if you have Continuation.new. You can write Continuation.new
using callcc, but you can’t write callcc using Continuation.new (without
having some magic stuff happen). callcc is more general.

Yeah, my only complaint with callcc is that the syntax you use if you want to
use it like my concept of Continuation.new (i.e. in a setjmp/longjmp way) is
really ugly. You have a block that doesn’t get used in a very block-like
manner, a variable being assigned a value in a way that seems like a
side-effect, etc.

I can now see that for certain uses of continuations, you need to be able to
assign a return location somewhere ahead of where you are now, which is why a
block is useful. But I think there are other cases where the block just
makes things confusing.

However, you can, of course, write a little extention that adds the
Continuation.new and Continuation.run methods for your own use, if you
find those more clear than callcc, which is a nice feature of Ruby.

Yup. If anybody else likes my extentions to the Continuation class, let me
know and I’ll wrap them up in an RAA project. If I’m the only one who
objects to the aesthetics of callcc, then I’ll just keep it for myself. But
before I do create an RAA project, I want to make sure that I didn’t miss a
subtlety and that my Continuation.new and Continuation.run will do everything
that you can currently do with callcc.

Thanks,

Ben

···

On Thu August 7 2003 10:31 pm, Dan Doel wrote:

Ahh, that’s where the confusion is! Callcc doesn’t stand for “call
continuation”. It is short for “call with current continuation”. In
other words, it calls a function passing in the current continuation.

I actually understood that – I just found it confusing. Offhand, I
can’t think of other Ruby classes that don’t have a constructor, and
can only be created by a method in an unrelated class or module.
Besides, it doesn’t precisely call a function passing the current
continuation, it yields to a block, passing in the current
continuation, if I understand things.

Actually, to me it seems that the Continuation.new syntax is the one
that is deceptive. For callcc doesn’t create a NEW continuation, it
just makes the existing continuation for the block available. All
function calls have a continuation (its the code that is executed when
the function returns). Callcc just makes that already existing
continuation available.

Right, but I’d argue that it is creating a “Continuation”. An object
of that class is being created, one which encapsulates the appropriate
state when callcc is used. It’s true that an abstract continuation is
created behind the scenes whenever a function is called, it’s just that
that process is internal to the interpreter, and not available to
programs.

I don’t think that Continuation.new is deceptive in how it acts,
although it is somewhat deceptive in how it is implemented.

Do you have any suggestions on how to improve my Continuation add-ons,
or are you happy with just using callcc?

Ben

···

On Friday, August 8, 2003, at 12:07 AM, Jim Weirich wrote:

Yup. If anybody else likes my extentions to the Continuation class, let me
know and I’ll wrap them up in an RAA project. If I’m the only one who
objects to the aesthetics of callcc, then I’ll just keep it for myself. But
before I do create an RAA project, I want to make sure that I didn’t miss a
subtlety and that my Continuation.new and Continuation.run will do everything
that you can currently do with callcc.

Well, Continuation.run seems to me to be trivially the same as callcc,
so you can do everything you can do with callcc with that alone.

As long as you’re tweaking, you could provide the style I mentioned
earlier of calling functions directly with callcc, like this:

def Continuation.run(*args)
callcc do |cc|
if block_given?
yield cc
else
func, *rest = args
if func.respond_to? :call
func.call(cc, *rest)
end
end
end
end

This lets you do something like:

def foo(cc, a, b)
puts a
cc.call b
end

puts Continuation.run(method(:foo), 1, 2)

Which prints

1
2

I don’t know if that’s desirable or not.

You could also do
if block_given?
yield cc, *args

To pass more arguments into the block if desired.

And like you, I’m not sure that I like Continuation.run as a name for
it, although I can’t come up with a good name either. I’d say
Continuation.call, but I think that’d be too corn-fusing.

Good luck.

  • Dan

[snip]

I actually understood that – I just found it confusing. Offhand, I
can’t think of other Ruby classes that don’t have a constructor, and
can only be created by a method in an unrelated class or module.

If they’re created, they have a constructor. The constructor is not
visible within Ruby. It is rare, except for the bootstrapping that gets
Ruby going in the beginning.

Besides, it doesn’t precisely call a function passing the current
continuation, it yields to a block, passing in the current
continuation, if I understand things.
[snip]

The block contains a function.

Regards,

Mark

···

On Friday, August 8, 2003, at 12:38 AM, Ben Giddings wrote:


The Master said: “Am I a man of great wisdom? Hardly! Even when a
simple person brings me a question, my mind goes utterly blank. I just
thrash it out until I’ve exhausted every possibility.”

Confucious, The Analects

Ben Giddings wrote:

Ahh, that’s where the confusion is! Callcc doesn’t stand for “call
continuation”. It is short for “call with current continuation”. In
other words, it calls a function passing in the current continuation.

I actually understood that – I just found it confusing. Offhand, I
can’t think of other Ruby classes that don’t have a constructor, and
can only be created by a method in an unrelated class or module.
Besides, it doesn’t precisely call a function passing the current
continuation, it yields to a block, passing in the current
continuation, if I understand things.

Actually, to me it seems that the Continuation.new syntax is the one
that is deceptive. For callcc doesn’t create a NEW continuation, it
just makes the existing continuation for the block available. All
function calls have a continuation (its the code that is executed when
the function returns). Callcc just makes that already existing
continuation available.

Right, but I’d argue that it is creating a “Continuation”. An object
of that class is being created, one which encapsulates the appropriate
state when callcc is used. It’s true that an abstract continuation is
created behind the scenes whenever a function is called, it’s just
that that process is internal to the interpreter, and not available to
programs.

I don’t think that Continuation.new is deceptive in how it acts,
although it is somewhat deceptive in how it is implemented.

Perhaps Continuation.new isn’t the right method name.

Maybe Continuation.capture, or something of that sort?

And if I may play devil’s advocate, Proc instances can be made from the
Kernel.proc or
Kernel.lambda methods, although I admit that there is Proc.new that does
the same thing.
MatchData objects are never constructed directly, as they are only the
result of regular
expression matching. It’s not unheard of, or even particularly
uncommon, to have object
oriented systems where certain objects are never constructed directly by
a constructor,
but are made by other methods in the class or even in another class. For
an example of
the latter, look at the Image class back in the Java 1.1 days. Back
then, the only ways
to get an Image object were to call Toolkit.getImage() or
Component.createImage(). I’m
not saying that’s a good design decision, but it does happen.

If you ask me, Kernel.callcc does make a lot of sense, since what you’re
effectively doing
is calling a function (okay, a proc, but they’re similar) in a special
way, which is related
to the more low-level aspects of the interpreter and such. Then again,
Proc.new exists,
and it has to create a closure, which seems fairly low level. But, I’m
getting off topic.

That doesn’t mean that callcc is intuitive for everyone, though, so if
it helps you to move
the functionality to Continuation, then it’s a good idea, at least for you.

Regards,

  • Dan
···

On Friday, August 8, 2003, at 12:07 AM, Jim Weirich wrote:

MatchData.

And Integer, Fixnum, Bignum, …

I agree with you though; even in those rare moments when I’ve thought
I’ve understood continuations, I ended up concluding that the Ruby
semantics were a bit misleading.

Gavin

···

On Friday, August 8, 2003, 2:38:05 PM, Ben wrote:

Ahh, that’s where the confusion is! Callcc doesn’t stand for “call
continuation”. It is short for “call with current continuation”. In
other words, it calls a function passing in the current continuation.

I actually understood that – I just found it confusing. Offhand, I
can’t think of other Ruby classes that don’t have a constructor, and
can only be created by a method in an unrelated class or module.

Moin!

Ben Giddings wrote:

Do you have any suggestions on how to improve my Continuation add-ons,
or are you happy with just using callcc?

I tried to make a simpler replacement to callcc and I ended up with this:

def Continuation.create(*args, &block)
cc = nil; result = callcc {|c| cc = c; nil}
result ||= args
return *[cc, *result]
end

I didn’t want to call this Continuation.new because it can return
multiple values.

Though the following simple examples are working well I would be
interested to know if the simpler syntax comes at the loss of
functionality.

  1. Word swapper:
    cc, first, second, called = Continuation.create(“Hello”, “World”)
    puts first + " " + second
    cc.call(second, first, true) unless called
    ^D
    Hello World
    World Hello

  2. Counter:
    cc, counter = Continuation.create(10)
    print counter, " "
    cc.call(counter - 1) if counter > 0
    puts
    ^D
    10 9 8 7 6 5 4 3 2 1 0

  3. Inject:
    module Enumerable
    def new_inject(initial=nil)
    array = self.dup
    initial = array.shift if initial.nil?
    cc, state, array = Continuation.create(initial, array)
    state = yield(state, array.shift)
    cc.call(state, array) if array.length > 0
    return state
    end
    end
    puts [1, 2, 3].new_inject {|state, item| state + item}
    ^D
    6

Regards,
Florian Groß

def foo(cc, a, b)
puts a
cc.call b
end

puts Continuation.run(method(:foo), 1, 2)

Which prints

1
2

Wouldn’t it print 1 and return 2?

Anyhow, I think that’s a worthwhile addition to the class. The only
thing that concerns me a bit about that way of doing things is that
it’s not completely clear that “foo” is a function that has to accept a
continuation as its first argument. You really want to not only check
to see if the object responds to “call” but to see if it is a subtype
of function that accepts a continuation as its first argument. This
makes me think of Java threading stuff, where you commonly test to see
if something implements the runnable interface. Maybe a better idea
might be a class like ContinuationConsumer(?) that stores the
continuation as a member variable:

class ContinuationConsumer
attr_accessor :cc

def call(first, second)

@cc.call( … )
end
end

def Continuation.run(*args)
callcc do |cc|
if block_given?
yield cc
else
func_or_obj, *rest = args
if func_or_obj.respond_to? :call
if func_or_obj.kind_of? ContinuationConsumer
func_or_obj.cc = cc
func_or_obj.call(*rest)
else
func_or_obj.call(cc, *rest)
end
end
end
end
end

I’m too tired to think this through properly right now, so I’m just
tossing it out there as is. This isn’t the duck-typing-ist way of
doing things, so any suggestions to make it cleaner or just overall
better would be welcome.

And like you, I’m not sure that I like Continuation.run as a name for
it, although I can’t come up with a good name either. I’d say
Continuation.call, but I think that’d be too corn-fusing.

Yeah, call is really what I keep wanting to name it, but I can’t
imagine it not being confusing. Maybe Continuation.use?

Ben

···

On Thursday, August 7, 2003, at 11:32 PM, Dan Doel wrote:

Actually, I think Proc.new {…} and proc {…} are no longer identical in
1.8.0. However I can’t remember what the subtle difference is. Even if I
could, I doubt I could remember which way round they were!

Regards,

Brian.

···

On Fri, Aug 08, 2003 at 02:05:31PM +0900, Dan Doel wrote:

And if I may play devil’s advocate, Proc instances can be made from the
Kernel.proc or
Kernel.lambda methods, although I admit that there is Proc.new that does
the same thing.

Continuation.resume?

martin

···

Dan Doel djd15@po.cwru.edu wrote:

And like you, I’m not sure that I like Continuation.run as a name for
it, although I can’t come up with a good name either. I’d say
Continuation.call, but I think that’d be too corn-fusing.

Ben Giddings wrote:

def foo(cc, a, b)
puts a
cc.call b
end

puts Continuation.run(method(:foo), 1, 2)

Which prints

1
2

Wouldn’t it print 1 and return 2?

Well, I did “puts Continuation.run(method(:foo), 1, 2)”, which prints
the 2 that it returns

Anyhow, I think that’s a worthwhile addition to the class. The only
thing that concerns me a bit about that way of doing things is that
it’s not completely clear that “foo” is a function that has to accept
a continuation as its first argument. You really want to not only
check to see if the object responds to “call” but to see if it is a
subtype of function that accepts a continuation as its first
argument. This makes me think of Java threading stuff, where you
commonly test to see if something implements the runnable interface.
Maybe a better idea might be a class like ContinuationConsumer(?) that
stores the continuation as a member variable:

class ContinuationConsumer
attr_accessor :cc

def call(first, second)

@cc.call( … )
end
end

def Continuation.run(*args)
callcc do |cc|
if block_given?
yield cc
else
func_or_obj, *rest = args
if func_or_obj.respond_to? :call
if func_or_obj.kind_of? ContinuationConsumer
func_or_obj.cc = cc
func_or_obj.call(*rest)
else
func_or_obj.call(cc, *rest)
end
end
end
end
end

I’m too tired to think this through properly right now, so I’m just
tossing it out there as is. This isn’t the duck-typing-ist way of
doing things, so any suggestions to make it cleaner or just overall
better would be welcome.

Well, you could do that, but as you said, it’s not exactly duck typing.
Presumably if someone’s
passing a function to callcc, it will expect a continuation as its first
argument, otherwise it wouldn’t
make sense to pass the function in the first place, so I wouldn’t worry
about callcc figuring out
if the function intends to use the arguments correctly (besides, you
don’t do that for all other
functions you call).

I like Java, but making “first-class functions” in it has always
bothered me. It essentially requires
creating a separate class/interface for each return type (each primitive
type and Object), which
is messy. Also, Runnable is only really around because 1 - Java is
statically typed and 2- the
thread needs to make sure that the object has a run() method. Runnable
is an efficient way
to do this in Java, but in Ruby it’s easy to use respond_to? for the
same purpose. Theoretically,
in Java you could use reflection to find out if an object has a run
method and call that method
without having the object implement the Runnable interface, but that’d
be slow and complex.

Ruby is much nicer in this regard.

And like you, I’m not sure that I like Continuation.run as a name for
it, although I can’t come up with a good name either. I’d say
Continuation.call, but I think that’d be too corn-fusing.

Yeah, call is really what I keep wanting to name it, but I can’t
imagine it not being confusing. Maybe Continuation.use?

I don’t think use, or even call is the right thing to call it.
Continuation.call_with_current would
be more accurate, if verbose. Or perhaps Continuation.pass_current_to.
The thing that bothers
me about any of these is that it doesn’t accurately portray what’s going
on. It would read better
if you could do something like:

fun(Continuation.current, arg1, arg2, …)

But there again that’s less generall than callcc, because it doesn’t let
you do anything like:

callcc { |cc|
# do stuff …
fun(cc, arg1, arg2, …)
}

That’s why call-with-current-continuation and callcc work the way they
do. They do what
they say they do and no more, but are general enough to do all the more
specific stuff.

I don’t know that either of us will be able to come up with a method
name that expresses
what’s going on well in Object.verb form.

The best I can come up with is Continuation.call_with_current_continuation
Or maybe:

Continuation.call_method_or_block_with_current_continuation_and_maybe_pass_some_arguments_too

:slight_smile:

It’s past my bed time.

  • Dan
···

On Thursday, August 7, 2003, at 11:32 PM, Dan Doel wrote:

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.

The problem with this that I see is that Continuation.current implies
the continuation of the currently executing function. For example, in
the following code …

def f
# Stuff
g(Continuation.current)
# More Stuff
end

def g(cc)
cc.call
end

The continuation call in g would not return to “More Stuff”, but to the
function calling f.

···

On Fri, 2003-08-08 at 01:42, Dan Doel wrote:

It would read better
if you could do something like:

fun(Continuation.current, arg1, arg2, …)


– Jim Weirich jweirich@one.net http://onestepback.org

“Beware of bugs in the above code; I have only proved it correct,
not tried it.” – Donald Knuth (in a memo to Peter van Emde Boas)