Class: Continuation
Overview
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( = arr.shift)
$cc.call unless =~ /Max/
produces:
Freddie
Herbie
Ron
Max
Also you can call callcc in other methods:
require "continuation"
def g
arr = [ "Freddie", "Herbie", "Ron", "Max", "Ringo" ]
cc = callcc { |cc| cc }
puts arr.shift
return cc, arr.size
end
def f
c, size = g
c.call(c) if size > 1
end
f
This (somewhat contrived) example allows the inner loop to abandon processing early:
require "continuation"
callcc {|cont|
for i in 0..4
print "#{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
-
#[](args, ...)
(also: #call)
Invokes the continuation.
-
#call(args, ...)
Alias for #[].
Instance Method Details
#call(args, ...)
#[](args, ...)
Also known as: #call
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 'cont.c', line 1620
static VALUE rb_cont_call(int argc, VALUE *argv, VALUE contval) { rb_context_t *cont = cont_ptr(contval); rb_thread_t *th = GET_THREAD(); if (cont_thread_value(cont) != th->self) { rb_raise(rb_eRuntimeError, "continuation called across threads"); } if (cont->saved_ec.protect_tag != th->ec->protect_tag) { rb_raise(rb_eRuntimeError, "continuation called across stack rewinding barrier"); } if (cont->saved_ec.fiber_ptr) { if (th->ec->fiber_ptr != cont->saved_ec.fiber_ptr) { rb_raise(rb_eRuntimeError, "continuation called across fiber"); } } rollback_ensure_stack(contval, th->ec->ensure_list, cont->ensure_array); cont->argc = argc; cont->value = make_passing_arg(argc, argv); cont_restore_0(cont, &contval); return Qnil; /* unreachable */ }
#call(args, ...)
#[](args, ...)
Alias for #[].