Class Continuation
In: eval.c
Parent: Object

Continuation objects are generated by Kernel#callcc. They hold a return address and execution context, allowing a nonlocal return to the end of the callcc block from anywhere within a program. Continuations are somewhat analogous to a structured version of C‘s setjmp/longjmp (although they contain more state, so you might consider them closer to threads).

For instance:

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

produces:

   Freddie
   Herbie
   Ron
   Max

This (somewhat contrived) example allows the inner loop to abandon processing early:

   callcc {|cont|
     for i in 0..4
       print "\n#{i}: "
       for j in i*5...(i+1)*5
         cont.call() if j == 17
         printf "%3d", j
       end
     end
   }
   print "\n"

produces:

   0:   0  1  2  3  4
   1:   5  6  7  8  9
   2:  10 11 12 13 14
   3:  15 16

Methods

[]   call  

Public Instance methods

Invokes the continuation. The program continues from the end of the callcc block. If no arguments are given, the original callcc returns nil. If one argument is given, callcc returns it. Otherwise, an array containing args is returned.

   callcc {|cont|  cont.call }           #=> nil
   callcc {|cont|  cont.call 1 }         #=> 1
   callcc {|cont|  cont.call 1, 2, 3 }   #=> [1, 2, 3]

[Source]

/*
 *  call-seq:
 *     cont.call(args, ...) 
 *     cont[args, ...]
 *  
 *  Invokes the continuation. The program continues from the end of the
 *  <code>callcc</code> block. If no arguments are given, the original
 *  <code>callcc</code> returns <code>nil</code>. If one argument is
 *  given, <code>callcc</code> returns it. Otherwise, an array
 *  containing <i>args</i> is returned.
 *     
 *     callcc {|cont|  cont.call }           #=> nil
 *     callcc {|cont|  cont.call 1 }         #=> 1
 *     callcc {|cont|  cont.call 1, 2, 3 }   #=> [1, 2, 3]
 */

static VALUE
rb_cont_call(argc, argv, cont)
    int argc;
    VALUE *argv;
    VALUE cont;
{
    rb_thread_t th = rb_thread_check(cont);

    if (th->thread != curr_thread->thread) {
        rb_raise(rb_eRuntimeError, "continuation called across threads");
    }
    if (th->thgroup != cont_protect) {
        rb_raise(rb_eRuntimeError, "continuation called across trap");
    }
    switch (argc) {
      case 0:
        th->result = Qnil;
        break;
      case 1:
        th->result = argv[0];
        break;
      default:
        th->result = rb_ary_new4(argc, argv);
        break;
    }

    rb_thread_restore_context(th, RESTORE_NORMAL);
    return Qnil;
}

Invokes the continuation. The program continues from the end of the callcc block. If no arguments are given, the original callcc returns nil. If one argument is given, callcc returns it. Otherwise, an array containing args is returned.

   callcc {|cont|  cont.call }           #=> nil
   callcc {|cont|  cont.call 1 }         #=> 1
   callcc {|cont|  cont.call 1, 2, 3 }   #=> [1, 2, 3]

[Source]

/*
 *  call-seq:
 *     cont.call(args, ...) 
 *     cont[args, ...]
 *  
 *  Invokes the continuation. The program continues from the end of the
 *  <code>callcc</code> block. If no arguments are given, the original
 *  <code>callcc</code> returns <code>nil</code>. If one argument is
 *  given, <code>callcc</code> returns it. Otherwise, an array
 *  containing <i>args</i> is returned.
 *     
 *     callcc {|cont|  cont.call }           #=> nil
 *     callcc {|cont|  cont.call 1 }         #=> 1
 *     callcc {|cont|  cont.call 1, 2, 3 }   #=> [1, 2, 3]
 */

static VALUE
rb_cont_call(argc, argv, cont)
    int argc;
    VALUE *argv;
    VALUE cont;
{
    rb_thread_t th = rb_thread_check(cont);

    if (th->thread != curr_thread->thread) {
        rb_raise(rb_eRuntimeError, "continuation called across threads");
    }
    if (th->thgroup != cont_protect) {
        rb_raise(rb_eRuntimeError, "continuation called across trap");
    }
    switch (argc) {
      case 0:
        th->result = Qnil;
        break;
      case 1:
        th->result = argv[0];
        break;
      default:
        th->result = rb_ary_new4(argc, argv);
        break;
    }

    rb_thread_restore_context(th, RESTORE_NORMAL);
    return Qnil;
}

[Validate]