Class: Continuation
Overview
Continuation objects are generated by Kernel#callcc, after having required 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( = arr.shift)
$cc.call unless =~ /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
Instance Method Summary collapse
-
#[](*args) ⇒ Object
Invokes the continuation.
-
#call(*args) ⇒ 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]
1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 |
# File 'cont.c', line 1049
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 */
}
|
#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]
1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 |
# File 'cont.c', line 1049
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 */
}
|