From: Logan Capaldo Date: 2006-02-08T07:19:27+09:00 Subject: Re: About Extending Systax Here's another go at it using continuations: % cat try_catch_throw.rb class Flow def initialize(parent = nil) @exceptions = [] @parent = parent @uncaught_exception = nil end def try(&block) @try_block = block end def throw(exception) caught = @exceptions.each do |key, value| if key === exception value.call(exception) break true end end unless caught == true if @parent @parent.throw(exception) else @uncaught_exception = exception end end @cc.call end def finally(&block) @finally = block self end def catch(exception, &block) @exceptions << [exception, block] self end def go callcc { |@cc| @try_block.call } if @finally @finally.call end if @uncaught_exception STDERR.puts "Uncaught exception: #{@uncaught_exception}" exit(1) end end end % cat test_flow.rb require 'try_catch_throw' handling2 = Flow.new handling2.try { handling3 = Flow.new(handling2) handling3.try { puts "Nested try" handling3.throw "ERROR! in handling3" } handling3.go } handling2.catch(String) do |exception| puts "handling2 Caught exception: #{exception}" end handling2.go handling = Flow.new handling.try { puts "Hello" handling.throw "ERROR!" puts "World" } handling.finally { puts "Finally" } handling.go % ruby test_flow.rb Nested try handling2 Caught exception: ERROR! in handling3 Hello Finally Uncaught exception: ERROR! At first I tried to do it without continuations but I couldn't think of a way to do so. Also the nesting is explicit which has the advantage of not using global vars and the disadvantage of excessive typing.