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}")