Ruby's catch/throw, goto's little brother
Posted by: on
Last week Pat Shaughnessy discovered that there’s a pre-processor definition in the Ruby 1.9 source code to enable goto and label statements in a rather ugly way:
The
__goto__statement will cause the MRI Ruby 1.9 interpreter to jump up to the__label__statement on the first line, since they both refer to the same symbol:loop.
I don’t think there’s much use for goto in a language like Ruby considering that it’s garbage collected and you can release resources using closures and ensure blocks. However, if you’re dying to play with this, why not use goto’s little brother, catch and throw:
class Test
def foo
throw(:label, "foo")
"should never get here"
end
def bar
"bar"
end
end
test = Test.new
puts("foo -> " + catch(:label) {test.foo})
puts("bar -> " + catch(:label) {test.bar})
There’s not much to know about catch and throw. You give a symbol and a block to catch, which acts like a goto label. Any code that uses throw in that block, no matter how deep, will unwind and cause the catch block to terminate, returning the value given to throw.
You can nest multiple catch and throw expressions using different values for the label symbol. Here’s another example:
def thrower
10.times do |i|
10.times do |j|
$stdout.puts("#{i}.#{j}")
throw(:label, j) if i > 2 and j > 2
end
end
end
val = catch(:label) do
thrower
raise("should never get here")
end
$stdout.puts("val is #{val}")
Topics: Ruby
