What Is Catch and Throw Used for in Ruby

What is catch and throw used for in Ruby?

You can use this to break out of nested loops.

INFINITY = 1.0 / 0.0
catch (:done) do
1.upto(INFINITY) do |i|
1.upto(INFINITY) do |j|
if some_condition
throw :done
end
end
end
end

If you had used a break statement above, it would have broken out of the inner loop. But if you want to break out of the nested loop, then this catch/throw would be really helpful. I have used it here to solve one of the Euler problems.

Where are catch and throw useful in Ruby?

Note: It looks like a few things have changed with catch/throw in 1.9. This answer applies to Ruby 1.9.

A big difference is that you can throw anything, not just things that are derived from StandardError, unlike raise. Something silly like this is legal, for example:

throw Customer.new

but it's not terribly meaningful. But you can't do:

irb(main):003:0> raise Customer.new
TypeError: exception class/object expected
from (irb):3:in `raise'
from (irb):3
from /usr/local/bin/irb:12:in `<main>'

ruby catch-throw and efficiency

In addition to being the "correct" way to get out of control structures, catch-throw is also significantly faster(10 times as fast in my testing). Check out this gist for my code and results.

What is the difference between Raising Exceptions vs Throwing Exceptions in Ruby?

I think http://hasno.info/ruby-gotchas-and-caveats has a decent explanation of the difference:

catch/throw are not the same as raise/rescue. catch/throw allows you to quickly exit blocks back to a point where a catch is defined for a specific symbol, raise rescue is the real exception handling stuff involving the Exception object.

Ruby Throw-Catch tutorial unclear

That final line promptAndGet("Name") does not get immediately executed, since it's after the catch block.

The normal flow is that everything within the catch :quitRequested block gets executed immediately, in order. That's why you get all 3 prompts inside. If you answer all 3 prompts, you'll also get to the prompt on the last line.

If you answer ! to any of the three prompts, the block will terminate. So you will not get the remaining prompts inside the block.

You'll still get the prompt on the last line since it's outside of the catch.

throw is what terminates the catch block - not what initiates it.

Also, if you answer ! to that final prompt outside of the catch block, you'll get an error, because the throw was uncaught.

Common way of error-handling when using an external ruby-library

In ruby, you raise an exception. The exception can be a class, an instance of a class, or a class and a string, and normally the class is a decendent of StandardError, which is a decendent of Exception. To catch an exception, you do this:

begin
raise StandardError, "weeee, exception!"
rescue StandardError => e # or => e for a general rescue
puts "Exception Message: #{e.message}"
end

Normally, the exception handling would be done outside the library so you'd only have to worry about the raise line. throw and catch still exist in ruby, but raise is the preferred method of exception handling.

What throwable can't be caught?

There are two types of error-handling flow in Ruby.

The most commonly used, and most flexible is begin...rescue

There is also throw and catch, which is much more lightweight. Some of the Rack libraries use this mechanism.

Most importantly, and sometimes annoyingly, the mechanisms are separate, and if a library uses throw...catch for program flow, you cannot intercept the messages using begin...rescue, therefore a rescue Exception block will not get executed.

In general you should not try and intercept third-party throw/catch, unless documentation suggests that you can. That is because the library will probably have modified env to set an error message/state. Instead, look for an equivalent method that does not work with Rack errors, but returns true or false for the conditions you are checking. For instance, perhaps the method user_signed_in? would be better.


Example of how catch works in Ruby:

puts 'a'
x = catch(:mysymbol) do
puts 'b'
throw :mysymbol, 'world'
puts 'c'
end
puts "hello #{x}"

prints

a
b
hello world


Related Topics



Leave a reply



Submit