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
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) { rb_fiber_t *fcont; GetFiberPtr(cont->saved_thread.fiber, fcont); if (th->fiber != cont->saved_thread.fiber) { rb_raise(rb_eRuntimeError, "continuation called across fiber"); } } 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) { rb_fiber_t *fcont; GetFiberPtr(cont->saved_thread.fiber, fcont); if (th->fiber != cont->saved_thread.fiber) { rb_raise(rb_eRuntimeError, "continuation called across fiber"); } } 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 */ }
Commenting is here to help enhance the documentation. For example, sample code, or clarification of the documentation.
If you are posting code samples in your comments, please wrap them in "<pre><code class="ruby" > ... </code></pre>" markup in order to get syntax highlighting.
If you have questions about Ruby or the documentation, please post to one of the Ruby mailing lists. You will get better, faster, help that way.
If you wish to post a correction of the docs, please do so, but also file a bug report so that it can be corrected for the next release. Thank you.