Why does Ruby have callcc?

Discussion in 'Ruby' started by Jim Bob, Aug 6, 2003.

  1. Jim Bob

    Jim Bob Guest

    I understand, in a woozy sort of way, what callcc does. What I
    don't understand is what it's really good for, and furthermore, what
    it's doing in Ruby.

    It seems like all the explanations of callcc, in its various
    implementations, stick to pretty simple examples, and almost always with
    the proviso "you could more easily do this another way, but...". The
    exception might be with regard to Scheme, which, I guess, lacks a
    catch/throw-like mechanism, so that callcc might be the best way to
    escape from a deeply nested loop. Ruby, though, obviously has catch and
    throw.

    With some other languages, I wouldn't think much of the inclusion of
    such an apparently abstruse feature. But, from my reading of this list,
    it seems like Matz is pretty conservative about adding features that
    won't get used, for whatever reason. I can only guess that he'd be twice
    less likely to add features that don't get used and are just plain
    *weird*, as callcc seems to me even after having spent no short amount
    of time trying to wrap my thick head around it.

    So, how'd it get there? Is there some killer use for callcc that I'm
    missing? Was it just for the "gee whiz" factor?
    Jim Bob, Aug 6, 2003
    #1
    1. Advertising

  2. Jim Bob

    Harry Ohlsen Guest

    Jim Bob wrote:

    > So, how'd it get there? Is there some killer use for callcc that I'm
    > missing? Was it just for the "gee whiz" factor?


    I'd be interested to read about some real-world examples where people have used callcc, not just to try it out, but because it was the "right" way to do something (for efficiency, or code brevity or whatever reason).

    So, as opposed to the examples we find on some of the Ruby web pages, which are, as Bob said, effectively tutorials on how one *might* use callcc, can someone give us some examples of production code they've written that uses continuations?
    Harry Ohlsen, Aug 6, 2003
    #2
    1. Advertising

  3. On Wed, Aug 06, 2003 at 08:38:25PM +0900, Harry Ohlsen wrote:
    > I'd be interested to read about some real-world examples where people have
    > used callcc, not just to try it out, but because it was the "right" way to
    > do something (for efficiency, or code brevity or whatever reason).


    I think Seaside/Borges falls into this category.

    I haven't had a chance to use it in anger, but I think the idea is that
    continuations can represent CGI session state; you code can be written in a
    linear fashion (e.g. display page, fetch response, display next page, fetch
    next response etc) without any explicit session maintenance. Furthermore, by
    retaining continuation objects which represent earlier pages, it will work
    even if the user clicks 'back' in their browser and re-enters data in a
    previous form.

    I'd have a number of concerns in a practical application - I'd want old
    continuations to expire and be garbage-collected so that they don't cause
    infinite memory growth - but otherwise it sounds like a great way to write
    web applications.

    Regards,

    Brian.
    Brian Candler, Aug 6, 2003
    #3
  4. Jim Bob

    Harry Ohlsen Guest

    Brian Candler wrote:

    > I think Seaside/Borges falls into this category.


    Do you have any URLs for this? I did a quick Google, but found a Smalltalk site. As far as I can tell, Seaside was some Ruby code that ended up in Smalltalk as Borges?

    H.
    Harry Ohlsen, Aug 6, 2003
    #4
  5. "Harry Ohlsen" <> schrieb im Newsbeitrag
    news:...
    > Jim Bob wrote:
    >
    > > So, how'd it get there? Is there some killer use for callcc that I'm
    > > missing? Was it just for the "gee whiz" factor?

    >
    > I'd be interested to read about some real-world examples where people

    have used callcc, not just to try it out, but because it was the "right"
    way to do something (for efficiency, or code brevity or whatever reason).

    Standalone iterators. Jim Weirich posted some code here about 1 or 2
    months ago. Maybe you'll find it here: http://onestepback.org/

    > So, as opposed to the examples we find on some of the Ruby web pages,

    which are, as Bob said, effectively tutorials on how one *might* use
    callcc, can someone give us some examples of production code they've
    written that uses continuations?

    http://www.rubygarden.org/ruby?ContinuationExplanation

    robert
    Robert Klemme, Aug 6, 2003
    #5
  6. On Wed, Aug 06, 2003 at 09:15:59PM +0900, Harry Ohlsen wrote:
    > Brian Candler wrote:
    >
    > > I think Seaside/Borges falls into this category.

    >
    > Do you have any URLs for this? I did a quick Google, but found a
    > Smalltalk site. As far as I can tell, Seaside was some Ruby code that
    > ended up in Smalltalk as Borges?


    No, it was the other way round :) Anyway,

    http://raa.ruby-lang.org/list.rhtml?name=borges links to
    http://segment7.net/ruby-code/borges/borges.html

    which in turn links to information on Seaside. Also search for 'seaside' or
    'borges' at http://ruby-talk.org/ as it's been discussed before.

    ISTR it uses Webrick, and since that's now part of ruby-1.8.0, it should be
    easier to install.

    Cheers,

    Brian.
    Brian Candler, Aug 6, 2003
    #6
  7. On Wed, Aug 06, 2003 at 10:25:31PM +0900, Brian Candler wrote:
    > ISTR it uses Webrick, and since that's now part of ruby-1.8.0, it should be
    > easier to install.


    Just installed, it was a doddle: you need 'installpkg-0.0.1' and
    'borges-0.2.0', then

    cd /usr/local/share/examples/ruby/borges
    ruby counter.rb

    and then point your web browser at
    http://yourmachine:7000/counter

    It doesn't work with 'back' in the way I thought though; if I increment to
    4, click back a few times, then click 'inc' on 1, I still get 5. But I have
    a lot to learn about this framework :)

    Also I couldn't get pagecounter.rb to work as-is; you need to change
    "counter2" to something which doesn't end with a number, e.g. "pagecounter"
    because a request to http://foo:7000/counter2 seems to be interpreted as
    'counter'.

    Cheers,

    Brian.
    Brian Candler, Aug 6, 2003
    #7
  8. Hi,

    In message "Re: Why does Ruby have callcc?"
    on 03/08/06, Dan Debertin <> writes:

    |> So, how'd it get there? Is there some killer use for callcc that I'm
    |> missing? Was it just for the "gee whiz" factor?
    |
    |I can't explain the "how'd it get there" part; I'll leave that to Matz
    |and friends.

    The official answer is "why not". I provide the features, you use
    them.
    matz.
    Yukihiro Matsumoto, Aug 6, 2003
    #8
  9. Jim Bob

    Ben Giddings Guest

    On Wed August 6 2003 11:34 am, Yukihiro Matsumoto wrote:
    > I provide the features, you use them.


    Heh, best quite ever.
    Ben Giddings, Aug 6, 2003
    #9
  10. Brian Candler wrote:
    > On Wed, Aug 06, 2003 at 08:38:25PM +0900, Harry Ohlsen wrote:
    >
    >>I'd be interested to read about some real-world examples where people have
    >>used callcc, not just to try it out, but because it was the "right" way to
    >>do something (for efficiency, or code brevity or whatever reason).

    >
    >
    > I think Seaside/Borges falls into this category.


    Yup, absolutely.

    > I haven't had a chance to use it in anger, but I think the idea is that
    > continuations can represent CGI session state; you code can be written in a
    > linear fashion (e.g. display page, fetch response, display next page, fetch
    > next response etc) without any explicit session maintenance. Furthermore, by
    > retaining continuation objects which represent earlier pages, it will work
    > even if the user clicks 'back' in their browser and re-enters data in a
    > previous form.


    That's a pretty decent summary.

    > I'd have a number of concerns in a practical application - I'd want old
    > continuations to expire and be garbage-collected so that they don't cause
    > infinite memory growth - but otherwise it sounds like a great way to write
    > web applications.


    They certainly are expired and GC'ed. And you can control how many
    continuations you keep around for a particular session. You can also
    control how long sessions hang around - or you could swap them to disk
    and keep them forever. Again, this is all speaking about the Smalltalk
    version since I haven't seent he Ruby code in quite some time and it may
    well be true that you have less control of these things there.

    If anyone's interested in discussing Seaside or the benefits of
    continuations further, the Seaside (Smalltalk people but others welcome)
    community is all on the mailing list which you can sign up for at:

    http://lists.squeakfoundation.org/listinfo/seaside

    Cheers,

    Julian
    Julian Fitzell, Aug 6, 2003
    #10
  11. Jim Bob

    Ben Giddings Guest

    I have been interested in these continuation-thingys for a while now, so now
    that the subject came up, I decided to take a good look.

    I now think I understand how they work, and when they might be used, but that
    still leaves a few questions:

    1) Why do they have the strange syntax they have
    2) Why don't they have more "meat" to them?

    I found a bunch of websites all talking about continuations:

    http://www.ai.mit.edu/~gregs/ll1-discuss-archive-html/threads.html#01372
    http://www.ps.uni-sb.de/~duchier/python/continuations.html
    ...

    The summary is that Continuations are essentially "goto with parameters", or
    even more simply, like setjmp, longjmp.

    To do continuations, you need to save the state of the VM at the "site of the
    continuation", and then be able to load that up when asked to do so. Given
    that, I am puzzled by the syntax they have in Ruby. First of all, why the
    block? In most of the examples I've seen, there doesn't seem to be a good
    reason to have a block. The only reason the block is necessary seems to be
    that the end of the block marks the location where Continuation#call will go
    to. Also, why are they created by Kernel.callcc? Why not Continuation.new,
    where the location from which to continue when the Continuation is called is
    the next expression after .new.

    The second issue is why Continuations have nothing but a .call method.
    Because they should encapsulate things like stack and program-counter values
    at the time of the call, it would seem to me like these are useful things to
    have available.

    Say, for instance, that Continuation had a "stack" accessor, it could return
    something similar to Kernel.caller(). Continuation could also have a
    "program_counter" attr_reader that would return some sort of binding object
    (or a symbol or something) that would represent the location in the program
    that would be jumped-to by .call. I think it would be interesting to be able
    to manipulate Continuations in more ways than just .calling them. Maybe keep
    an array of them around and jump to the one with the smallest stack? I don't
    know.

    While I'm busy redesigning the language, what if Kernel.caller could return an
    array of Continuation objects, any of which could be .called? If I
    understand things correctly calling a continuation is essentially no
    different from returning from a method call. The PC is set to a certain
    address, the stack is unwound one level, and the only difference is that a
    certain value is held somewhere (in a register?)

    Anyhow, before today I really didn't know anything about Continuations, so
    maybe what I'm saying makes no sense at all, but I'd like to hear any
    comments on the subject.

    Ben
    Ben Giddings, Aug 6, 2003
    #11
  12. Jim Bob

    Dan Sugalski Guest

    At 7:27 AM +0900 8/7/03, Ben Giddings wrote:
    >I have been interested in these continuation-thingys for a while now, so now
    >that the subject came up, I decided to take a good look.
    >
    >I now think I understand how they work, and when they might be used, but that
    >still leaves a few questions:
    >
    >1) Why do they have the strange syntax they have


    They don't--there's no inherent strange syntax to them. The syntax
    comes from the language implementing the continuation semantics.

    >2) Why don't they have more "meat" to them?


    Because there's not much to them. Really, there isn't. Continuations
    (or, as I have recently been scolded about, first class
    continuations) are pretty simple things.

    >I found a bunch of websites all talking about continuations:
    >
    >http://www.ai.mit.edu/~gregs/ll1-discuss-archive-html/threads.html#01372
    >http://www.ps.uni-sb.de/~duchier/python/continuations.html
    >...
    >
    >The summary is that Continuations are essentially "goto with parameters", or
    >even more simply, like setjmp, longjmp.


    Well... no. that's not quite right. There's rather more to
    continuations than just that. Continuations are more a Location with
    Environment and History. Closures are Locations with Environment, and
    Functions are just Locations.

    >The second issue is why Continuations have nothing but a .call method.
    >Because they should encapsulate things like stack and program-counter values
    >at the time of the call, it would seem to me like these are useful things to
    >have available.


    It's generally considered Really Evil to look at anything inside a
    continuation. Darned useful, though...
    --
    Dan

    --------------------------------------"it's like this"-------------------
    Dan Sugalski even samurai
    have teddy bears and even
    teddy bears get drunk
    Dan Sugalski, Aug 6, 2003
    #12
  13. ----- Original Message -----
    From: "Dan Sugalski" <>
    To: "ruby-talk ML" <>
    Sent: Wednesday, August 06, 2003 5:45 PM
    Subject: Re: Why does Ruby have callcc?


    > At 7:27 AM +0900 8/7/03, Ben Giddings wrote:
    > >I have been interested in these continuation-thingys for a while now, so

    now
    > >that the subject came up, I decided to take a good look.
    > >
    > >I now think I understand how they work, and when they might be used, but

    that
    > >still leaves a few questions:
    > >
    > >1) Why do they have the strange syntax they have

    >
    > They don't--there's no inherent strange syntax to them. The syntax
    > comes from the language implementing the continuation semantics.


    Well, be fair. He's talking about continuations *in Ruby* --
    why do they look they way they do from a language user's
    perspective?

    And I have to agree with him -- it's unintuitive to me why
    there should be a block as opposed to just a "Continuation.new"
    call. And likewise I don't understand why callcc is in Kernel.

    Hal

    --
    Hal Fulton
    Hal E. Fulton, Aug 6, 2003
    #13
  14. Jim Bob

    Ben Giddings Guest

    On Wed August 6 2003 6:45 pm, Dan Sugalski wrote:
    > >1) Why do they have the strange syntax they have

    >
    > They don't--there's no inherent strange syntax to them. The syntax
    > comes from the language implementing the continuation semantics.


    Like Hal said, I meant why do they have the strange syntax they do "in Ruby".
    There just doesn't seem to be a good reason for a block. It also seems
    strange to have a class with no constructor that can only be created by a
    Kernel method.

    Is there some reason that Continuation.new couldn't work?

    > Well... no. that's not quite right. There's rather more to
    > continuations than just that. Continuations are more a Location with
    > Environment and History. Closures are Locations with Environment, and
    > Functions are just Locations.


    Ok, thanks. That's a good simplification of what I think I meant to say. :)

    > It's generally considered Really Evil to look at anything inside a
    > continuation. Darned useful, though...


    I like being evil. ;)

    I can imagine it being truly evil to be able to *change* a Continuation, but
    it doesn't strike me as terribly evil to look inside them. Even if the only
    (programmer accessible) extra information them was similar to what you get
    out of Kernel.caller. That way you could say something like:

    puts "About to call the continuation %p" % the_continuation

    And get something useful out of it.

    Comments?

    Ben
    Ben Giddings, Aug 7, 2003
    #14
  15. Jim Bob

    Eric Hodel Guest

    --J2pR2RtFp0tAjF3C
    Content-Type: text/plain; charset=us-ascii
    Content-Disposition: inline
    Content-Transfer-Encoding: quoted-printable

    Ben Giddings () wrote:

    > On Wed August 6 2003 6:45 pm, Dan Sugalski wrote:
    > > >1) Why do they have the strange syntax they have

    > >=20
    > > They don't--there's no inherent strange syntax to them. The syntax=20
    > > comes from the language implementing the continuation semantics.

    >=20
    > Like Hal said, I meant why do they have the strange syntax they do "in Ru=

    by". =20
    > There just doesn't seem to be a good reason for a block. It also seems=

    =20
    > strange to have a class with no constructor that can only be created by a=

    =20
    > Kernel method.


    The advantage to the block is that it allows you to do some stuff
    with the continuation (like saving this potential chain of execution)
    without continuaing. Not having the block makes things much more
    difficult.

    Take a look at the guts of Borges, particuarly Session.rb.

    http://segment7.net/ruby-code/borges/borges.html


    If you read below, you'll see the continuation captures what you're
    doing in respond, and saves it, and doesn't return until you invoke
    that continuation. The block allows you to do some stuff, *then*
    invoke, but only if you really want to in the convenient ruby
    metaphor.

    You may have to read more of the code to really understand what's
    going on here, I only understand enough of it to have an intuitive
    feel for the deep magic that's going on inside. I couldn't rewrite it
    from scratch.

    class Session

    # ...

    def handle_request_intern(request, response)
    @response =3D response
    @current_key =3D request.action_key
    callcc do |cc|
    @short_jmp =3D cc # *** note this
    if cont =3D @continuations[@current_key]
    # if there is a continuation for current_key, invoke
    cont.call(request)
    else
    # handle unknown requests
    unknown_request(request)
    end
    end
    @last_key =3D @current_key
    end

    # ...

    def respond
    callcc do |cc|
    @response.action_key =3D @continuations.store(cc)
    yield(@response)
    @short_jmp.call # *** is used here
    end
    end

    end

    And this code gets used in Renderer.rb:

    def render_response
    @callbacks =3D CallbackStore.new
    request =3D respond do |res|
    @response =3D @stream =3D res
    yield(self)
    end
    @callbacks.process_callbacks(request)
    end

    def text_input(value, attrs=3D{}, &update)
    attrs["value"] =3D value
    # This only gets invoked if this action is chosen.
    attrs["name"] =3D @callbacks.register_callback(update)
    input("text", attrs)
    end

    > Is there some reason that Continuation.new couldn't work?


    I don't know if this is 100% correct:

    class Continuation
    def self.new
    if block_given? then
    callcc { |c| yield(c) }
    else
    callcc { |c| return c }
    end
    end
    end


    --=20
    Eric Hodel - - http://segment7.net
    All messages signed with fingerprint:
    FEC2 57F1 D465 EB15 5D6E 7C11 332A 551C 796C 9F04


    --J2pR2RtFp0tAjF3C
    Content-Type: application/pgp-signature
    Content-Disposition: inline

    -----BEGIN PGP SIGNATURE-----
    Version: GnuPG v1.2.2 (FreeBSD)

    iD8DBQE/MZJ4MypVHHlsnwQRAqDqAKCUF+D2Vtm8aZ5xpsAxq4/Xfyt9HwCfdNgY
    KmDMkK1c+XXDc/nfNCgEJw8=
    =+fMR
    -----END PGP SIGNATURE-----

    --J2pR2RtFp0tAjF3C--
    Eric Hodel, Aug 7, 2003
    #15
  16. Jim Bob

    Eric Hodel Guest

    --V3eawNQxI9TAjvgi
    Content-Type: text/plain; charset=us-ascii
    Content-Disposition: inline
    Content-Transfer-Encoding: quoted-printable

    Eric Hodel () wrote:

    > Ben Giddings () wrote:
    >=20
    > > Is there some reason that Continuation.new couldn't work?

    >=20
    > I don't know if this is 100% correct:
    >=20
    > class Continuation
    > def self.new
    > if block_given? then
    > callcc { |c| yield(c) }
    > else
    > callcc { |c| return c }
    > end
    > end
    > end


    Oh yes, and there is this problem:

    irb(main):007:0> c =3D Continuation.new; puts 'hi'
    hi
    =3D> nil
    irb(main):008:0> c.call
    hi
    =3D> nil
    irb(main):009:0> c.call
    NoMethodError: undefined method `call' for nil
    from (irb):9

    Which is easily avoided with the block:

    irb(main):012:0> cx =3D nil
    =3D> nil
    irb(main):013:0> callcc { |c| cx =3D c }; puts 'hi'
    hi
    =3D> nil
    irb(main):014:0> cx.call
    hi
    =3D> nil
    irb(main):015:0> cx.call
    hi
    =3D> nil
    irb(main):016:0> cx.call
    hi
    =3D> nil

    The block makes this easy.

    --=20
    Eric Hodel - - http://segment7.net
    All messages signed with fingerprint:
    FEC2 57F1 D465 EB15 5D6E 7C11 332A 551C 796C 9F04


    --V3eawNQxI9TAjvgi
    Content-Type: application/pgp-signature
    Content-Disposition: inline

    -----BEGIN PGP SIGNATURE-----
    Version: GnuPG v1.2.2 (FreeBSD)

    iD8DBQE/MZTsMypVHHlsnwQRAvimAKDposWIsPsibsrCZuigLmKHedLB5QCdFJ0T
    hkuwKgMvGjc8Bn5ig2m+oR8=
    =rFLu
    -----END PGP SIGNATURE-----

    --V3eawNQxI9TAjvgi--
    Eric Hodel, Aug 7, 2003
    #16
  17. Jim Bob

    Jim Weirich Guest

    On Wed, 2003-08-06 at 10:42, Robert Klemme wrote:

    > Standalone iterators. Jim Weirich posted some code here about 1 or 2
    > months ago. Maybe you'll find it here: http://onestepback.org/


    You are probably refering to the "Same Fringe" problem ... you'll find
    it at http://jimweirich.umlcoop.net/articles/same_fringe/index.html


    --
    -- Jim Weirich 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)
    Jim Weirich, Aug 7, 2003
    #17
  18. Jim Bob

    Jim Weirich Guest

    On Wed, 2003-08-06 at 19:12, Ben Giddings wrote:
    > Like Hal said, I meant why do they have the strange syntax they do "in Ruby".
    > There just doesn't seem to be a good reason for a block.


    Continuations come out of a style of programming called Continuation
    Passing Style (CPS) where the continuation to a function is explicitly
    passed as an argument to the function. A continuation is essentially
    the code that will be executed when the function returns. By explicitly
    capturing a continuation and passing it as an argument, a normal
    recursive function can be turned in to a tail recursive function and
    there are interesting optimizations that can be done at that point. Dan
    Sugalski has some writeups in his "What the Heck is ... " series at:
    http://www.sidhe.org/~dan/blog.

    Since a continuation is related to a function invocation, when you ask
    for a continuation object you need to specify which function invocation
    the continuation is for. callcc addresses this by invoking the block,
    and passing the continuation of the block's invocation to the block
    itself. Since callcc "knows" it needs the continuation before the block
    is invoked, I suspect that it might be easier for the implementor than
    if the continuation of just *any* function invocation could be grabbed.

    I played around with a CPS solution to PragDave's Kata 2 (see
    http://pragprog.com/pragdave/Practices/Kata/KataTwo.rdoc,v). You can
    find my writeups at
    http://onestepback.org/index.cgi/Tech/Programming/Kata. The third,
    fourth and fifth entries deal with CPS, tail recursion and callcc.

    --
    -- Jim Weirich 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)
    Jim Weirich, Aug 7, 2003
    #18
  19. Hi,

    In message "Re: Why does Ruby have callcc?"
    on 03/08/07, Mauricio Fernández <> writes:

    |How consistent is this w/ your "no featuritis" policy? In LL2 you had
    |to explain why Ruby had callcc but no macros; your answer was that the
    |latter are more easily abused ("too powerful" IIRC).

    There's strong reason not to have macros in Ruby, as I believe.
    Continuation does not harm you very much.

    |Do you still believe that or does "I provide the features, you use them"
    |represent a new policy?

    I provide the features (which I choose), you use them.

    matz.
    Yukihiro Matsumoto, Aug 7, 2003
    #19
  20. Rudolf Polzer <> wrote:
    > case $lineno
    > when 100; puts "Hello World"
    > when 110; $i = 0
    > when 120; if $i > 10 then goto 160 end
    > when 130; puts "Current $i: %d" % [$i]
    > when 140; $i = $i + 1
    > when 150; goto 120
    > when 160; puts "Done!"
    > when 170; stop
    > end


    Best piece of fallthrough abuse since Duff :)

    martin
    Martin DeMello, Aug 7, 2003
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Mr. SweatyFinger
    Replies:
    2
    Views:
    1,739
    Smokey Grindel
    Dec 2, 2006
  2. zuzu
    Replies:
    14
    Views:
    228
    Phil Tomson
    Aug 23, 2004
  3. Mikael Brockman
    Replies:
    2
    Views:
    122
    Mikael Brockman
    Sep 25, 2004
  4. Bill Atkins

    callcc Semantics

    Bill Atkins, Oct 18, 2004, in forum: Ruby
    Replies:
    2
    Views:
    88
    Eric Hodel
    Oct 19, 2004
  5. Greg Fitzgerald

    Callcc problem in Generator

    Greg Fitzgerald, Jan 25, 2005, in forum: Ruby
    Replies:
    0
    Views:
    173
    Greg Fitzgerald
    Jan 25, 2005
Loading...

Share This Page