On this page
class Continuation
Continuation objects are generated by Kernel#callcc, after having +require+d continuation. 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:
require "continuation"
arr = [ "Freddie", "Herbie", "Ron", "Max", "Ringo" ]
callcc{|cc| $cc = 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:
require "continuation"
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
}
puts
produces:
0: 0 1 2 3 4
1: 5 6 7 8 9
2: 10 11 12 13 14
3: 15 16
Public Instance Methods
static VALUE
rb_cont_call(int argc, VALUE *argv, VALUE contval)
{
rb_context_t *cont;
rb_thread_t *th = GET_THREAD();
GetContPtr(contval, cont);
if (cont->saved_thread.self != th->self) {
rb_raise(rb_eRuntimeError, "continuation called across threads");
}
if (cont->saved_thread.protect_tag != th->protect_tag) {
rb_raise(rb_eRuntimeError, "continuation called across stack rewinding barrier");
}
if (cont->saved_thread.fiber) {
if (th->fiber != cont->saved_thread.fiber) {
rb_raise(rb_eRuntimeError, "continuation called across fiber");
}
}
rollback_ensure_stack(contval, th->ensure_list, cont->ensure_array);
cont->argc = argc;
cont->value = make_passing_arg(argc, argv);
/* restore `tracing' context. see [Feature #4347] */
th->trace_arg = cont->saved_thread.trace_arg;
cont_restore_0(cont, &contval);
return Qnil; /* unreachable */
}
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]
static VALUE
rb_cont_call(int argc, VALUE *argv, VALUE contval)
{
rb_context_t *cont;
rb_thread_t *th = GET_THREAD();
GetContPtr(contval, cont);
if (cont->saved_thread.self != th->self) {
rb_raise(rb_eRuntimeError, "continuation called across threads");
}
if (cont->saved_thread.protect_tag != th->protect_tag) {
rb_raise(rb_eRuntimeError, "continuation called across stack rewinding barrier");
}
if (cont->saved_thread.fiber) {
if (th->fiber != cont->saved_thread.fiber) {
rb_raise(rb_eRuntimeError, "continuation called across fiber");
}
}
rollback_ensure_stack(contval, th->ensure_list, cont->ensure_array);
cont->argc = argc;
cont->value = make_passing_arg(argc, argv);
/* restore `tracing' context. see [Feature #4347] */
th->trace_arg = cont->saved_thread.trace_arg;
cont_restore_0(cont, &contval);
return Qnil; /* unreachable */
}
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]
Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.