Class: Continuation
Overview
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( = arr.shift)
$cc.call unless =~ /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
Instance Method Summary collapse
-
#[] ⇒ Object
Invokes the continuation.
-
#call ⇒ Object
Invokes the continuation.
Instance Method Details
#call(args, ...) ⇒ Object #[](args, ...) ⇒ Object
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]
|
# File 'eval.c'
/*
* 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_cont_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;
}
|
#call(args, ...) ⇒ Object #[](args, ...) ⇒ Object
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]
|
# File 'eval.c'
/*
* 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_cont_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;
}
|