Ruby has two different exceptions mechanisms: Throw/Catch and Raise/Rescue.
Why do we have two?
When should you use one and not the other?
raise, fail, rescue, and ensure handle errors, also known as exceptions
throw and catch are control flow
Unlike in other
languages, Ruby’s throw and catch are not used for exceptions.
Instead, they provide a way to terminate execution early when no
further work is needed.
(Grimm, 2011)
Terminating a single level of control flow, like a while loop, can be done with a simple return. Terminating many levels of control flow, like a nested loop, can be done with throw.
While the exception mechanism of raise and rescue is great for abandoning execution when things go wrong, it's sometimes nice to be able to jump out of some deeply nested construct during normal processing. This is where catch and throw come in handy.
(Thomas and Hunt, 2001)
References
Grimm, Avdi. "Throw, Catch, Raise, Rescue… I’m so Confused!" RubyLearning Blog. N.p., 11 July 2011. Web. 1 Jan. 2012. http://rubylearning.com/blog/2011/07/12/throw-catch-raise-rescue--im-so-confused/.
Thomas, Dave, and Andrew Hunt. "Programming Ruby." : The Pragmatic Programmer's Guide. N.p., 2001. Web. 29 Sept. 2015. http://ruby-doc.com/docs/ProgrammingRuby/html/tut_exceptions.html.
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.
https://coderwall.com/p/lhkkug/don-t-confuse-ruby-s-throw-statement-with-raise offers an excellent explanation that I doubt I can improve on. To summarize, nicking some code samples from the blog post as I go:
raise/rescue are the closest analogues to the throw/catch construct you're familiar with from other languages (or to Python's raise/except). If you've encountered an error condition and you would throw over it in another language, you should raise in Ruby.
Ruby's throw/catch lets you break execution and climb up the stack looking for a catch (like raise/rescue does), but isn't really meant for error conditions. It should be used rarely, and is there just for when the "walk up the stack until you find a corresponding catch" behaviour makes sense for an algorithm you're writing but it wouldn't make sense to think of the throw as corresponding to an error condition.
What is catch and throw used for in Ruby? offers some suggestions on nice uses of the throw/catch construct.
The concrete behavioural differences between them include:
rescue Foo will rescue instances of Foo including subclasses of Foo. catch(foo) will only catch the same object, Foo. Not only can you not pass catch a class name to catch instances of it, but it won't even do equality comparisons. For instance
catch("foo") do
throw "foo"
end
will give you an UncaughtThrowError: uncaught throw "foo" (or an ArgumentError in versions of Ruby prior to 2.2)
Multiple rescue clauses can be listed...
begin
do_something_error_prone
rescue AParticularKindOfError
# Insert heroism here.
rescue
write_to_error_log
raise
end
while multiple catches need to be nested...
catch :foo do
catch :bar do
do_something_that_can_throw_foo_or_bar
end
end
A bare rescue is equivalent to rescue StandardError and is an idiomatic construct. A "bare catch", like catch() {throw :foo}, will never catch anything and shouldn't be used.
Related
So, for hashes in Ruby you can use hashrockets like this:
corned_beef = {
:ingredient1 => "beef",
:ingredient2 => "potatoes"
}
or the more concise json-ish style.
corned_beef = {
ingredient1: "beef",
ingredient2: "potatoes"
}
Is there a json-ish styled way to catch Ruby exceptions? The normal way is this:
begin
# ...blah blah...
rescue ActiveRecord::RecordNotFound => e
logger.debug { "Where's da beef?" }
rescue => e
logger.debug { "#{e.message}\nBacktrace Begin:\n #
{e.backtrace.join("\n")}" }
else
# ...blah blah...
end
I've started to hate seeing hashrockets in my code, even for this. Someone please educated me.
EDIT:
For some reason, this has attracted comments from the kind of people who have code-religious arrogant condescending judgement. This is a forum for questions, if you don't like the question, kindly close your window. Ruby was optimized for programmer happiness. My question is seeking what I deem cleaner sexier code. What is not wanted is an expression of lots of opinions that do nothing toward helping achieve an answer. I am a good programmer with legacy code that has been in production serving billions and is probably older than most of you. Please stop shoveling pointless opinions if it doesn't answer the question. So far, it doesn't look like what I'm seeking exists. That's fine.
If you absolutely want to get rid of it, you can fall back to some of Ruby's Global Variables, specifically
$!
The exception information message set by 'raise'.
$#
Array of backtrace of the last exception thrown.
begin
raise ArgumentError, 'Your argument is invalid'
rescue ArgumentError
puts "#{$!.message}\nBacktrace Begin:\n#{$#.join("\n")}"
# or
puts "#{$!.message}\nBacktrace Begin:\n#{$!.backtrace.join("\n")}"
end
I've never used any of the globals in an any real applications, so not sure what type of things you might want to watch out for (if multiple threads throwing different errors simultaneously* might be an issue, for example).
No, AFAIK this is the syntax required for creating a reference to the caught exception.
Learning ruby here, how can I use if an error was raised to control an if/else statement. In ruby pseudocode it would be something like.
if block.call raise?
#if block doesn't exist and an error is raised do this
else
#if block does exist do this
end
You could use an inline rescue like this:
if block.call rescue false
else
end
Though you shouldn't do this. The reason being that this will rescue any error in the block. Say you you mispelled some word in the block definition. Your code will act like this is intended, and you might have a hard time tracking it down.
In this case, to check if the block was given you can simply say if block. If you're using yield instead of the &block parameter, you can use the special method if block_given?.
Of course you can achieve conditional logic using rescues, but that's not what they're intended for, and it's not making things much simpler in most cases.
If I wanted to both rescue a potential error and catch a potential throw, how should I nest them? Are the two below equivalent, and it is just a matter of preference?
begin
catch(:some_throw) do
...
end
rescue SomeError
...
end
catch(:some_throw) do
begin
...
rescue SomeError
...
end
end
Its an opinion-based question, and one can argue either way. So, in my opinion...
If you are planning to return a value via throw, then, second option seems useful as it will let you rescue an error and throw some kind of default value.
Even if you were using throw and catch just to manage loop iterations and breaking out of it on certain conditions, second option still seems more readable and encapsulates all the logic inside the catch block.
They are not entirely equivalent. With the first alternative, the catch will only intercept values being thrown in the begin clause, while the second includes ones from rescue too.
That being said, if you are in the case, when the two are equivalent (aka you don't throw :some_throw in the rescue clause):
The argument for the first alternative would be that we tend to think that begin - rescue blocks enclose "regular" statements. throw - catch being rarely used and having a non-error semantic are more "regular"-y.
The argument for the second alternative would be that one should strive to enclose the least amount (only the possibly failing) of code in begin - rescue clauses.
Personally, I like the first one better.
Since there is no type in ruby, how do Ruby programmers make sure a function receives correct arguments? Right now, I am repeating if object.kind_of/instance_of statements to check and raise runtime errors everywhere, which is ugly. There must be a better way of doing this.
My personal way, which I am not sure if it a recommended way in general, is to type-check and do other validations once an error occurs. I put the type check routine in a rescue block. This way, I can avoid performance loss when correct arguments are given, but still give back the correct error message when an error occurs.
def foo arg1, arg2, arg3
...
main_routine
...
rescue
## check for type and other validations
raise "Expecting an array: #{arg1.inspect}" unless arg1.kind_of?(Array)
raise "The first argument must be of length 2: #{arg1.inspect}" unless arg1.length == 2
raise "Expecting a string: #{arg2.inspect}" unless arg2.kind_of?(String)
raise "The second argument must not be empty" if arg2.empty?
...
raise "This is `foo''s bug. Something unexpected happened: #{$!.message}"
end
Suppose in the main_routine, you use the method each on arg1 assuming that arg1 is an array. If it turns out that it is something else, to which each is not defined, then the bare error message will be something like method each not defined on ..., which, from the perspective of the user of the method foo, might be not helpful. In that case, the original error message will be replaced by the message Expecting an array: ..., which is much more helpful.
Ruby is, of course, dynamically typed.
Thus the method documentation determines the type contract; the type-information is moved from the formal type-system to the [informal type specification in the] method documentation. I mix generalities like "acts like an array" and specifics such as "is a string". The caller should only expect to work with the stated types.
If the caller violates this contract then anything can happen. The method need not worry: it was used incorrectly.
In light of the above, I avoid checking for a specific type and avoid trying to create overloads with such behavior.
Unit-tests can help ensure that the contract works for expected data.
If a method has a reason to exist, it will be called.
If reasonable tests are written, everything will be called.
And if every method is called, then every method will be type-checked.
Don't waste time putting in type checks that may unnecessarily constrain callers and will just duplicate the run-time check anyway. Spend that time writing tests instead.
I recommend to use raise at the beginning of the method to add manual type checking, simple and effective:
def foo(bar)
raise TypeError, "You called foo without the bar:String needed" unless bar.is_a? String
bar.upcase
end
Best way when you don't have much parameters, also a recommendation is to use keyword arguments available on ruby 2+ if you have multiple parameters and watch for its current/future implementation details, they are improving the situation, giving the programmer a way to see if the value is nil.
plus: you can use a custom exception
class NotStringError < TypeError
def message
"be creative, use metaprogramming ;)"
#...
raise NotStringError
You can use a Design by Contract approach, with the contracts ruby gem. I find it quite nice.
whenever there is an exception call that is raised, the script terminates.
do i have to resort to putting each action ? it gets very complicated fast.....
begin
#someaction
begin
#someaction2
rescue
end
rescue
end
You could use some sort of AOP mechanism to surround every method call with exception handling code (like Aquarium: http://aquarium.rubyforge.org/), or put rescue nil after every line of code, but I'm guessing that if you need to do that, then the exceptions raised are not really signalling exceptional situations in your app (which is bad) or you want to try to continue even in a situation where there's really no point to do so (which is even worse). Anyway I'd advise you to reconsider what you really need to do, because it seems to me that you are approaching the problem in a wrong way.
It's difficult to give a specific answer because I don't know what your program does.
But in general terms, I find that the best way to deal with this is to put the code that could fail into one or more seperate methods (and perhaps the method name should reflect this).
This has a number of advantages. First of all, it means that the rest of your code doesn't have to be hedged around with exception handling; secondly, if the "dangerous" actions are carefully split up into logical groups, you may be able to do exception handling on the method, not the actual actions. Stupid example:
my_list = get_list("one") # perfectly safe method
my_list.each do |x|
begin
x.dangerous_file_method() # dangerous method
rescue
x.status = 1
end
end