Here's an example I came up with today while investigating continuations. Hope this is useful to somebody trying to understand and use them. Feedback welcome! Output: lizzy:~% ./continuation-example.rb 1 2 exception seen, performing error handling (elem=3) continuing 4 5 exception seen, performing error handling (elem=6) continuing 7 8 exception seen, performing error handling (elem=9) continuing lizzy:~% Code: #!/usr/bin/env ruby # Have you ever had the problem of wanting to report some error condition from # deep down within a set of nested method calls, but also wanting processing # to continue right after the spot where the error occurred, after the error # is reported and handled in the caller? # # While there are other ways to do this (e.g. using callbacks), this example # shows how to do this using exceptions and continuations. The trick is to # have the exception propagate the continuation to the appropriate caller # which can then handle the error (print an error message, say) and cause # processing to continue inside the method that saw the error by calling the # continuation passed up. # # This code uses a Reader class instance to process a list of elements # (numbers) using a screening function. The processing is facilitated using # the Reader.each method. Inside this method, if the element passes screening # it is yielded to the caller, else an exception is raised. The caller # processes the exception, then causes processing to continue inside the # Reader.each method, while passing a hint into it telling it how to continue. # In this particular example, the screening test consists of checking whether # a list element is divisible by 3, if which case it is considered "bad". # Also, when a maximum of 3 errors is seen (as indicated by the caller) # processing of list elements stops. MAX_ERRORS = 3 class CCException < Exception attr_reader :cc, :elem def initialize(cc, elem) @cc, @elem = cc, elem end end class Reader def initialize(arr) @arr = arr end def each(check) cc = nil @arr.each do |elem| if check.call(elem) ok_to_continue = Kernel.callcc do |cc| raise CCException.new(cc, elem) end break unless ok_to_continue else yield elem end end end end list = [1,2,3,4,5,6,7,8,9,10,11,12] rdr = Reader.new(list) errors = 0 # Returns whether we consider an element 'bad' check = proc {|elem| elem % 3 == 0} begin rdr.each(check) do |elem| puts elem end rescue CCException => exc errors += 1 puts "exception seen, performing error handling (elem=#{exc.elem})" # ...error handling... puts "continuing" exc.cc.call(errors < MAX_ERRORS) end exit -- Jos Backus jos at catnook.com