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

53,919

Solution 1

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.

Solution 2

  • 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

  1. 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/.
  2. 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.

Solution 3

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:

  1. 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.

  2. 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.

Share:
53,919

Related videos on Youtube

Nick Retallack
Author by

Nick Retallack

Updated on January 09, 2020

Comments

  • Nick Retallack
    Nick Retallack over 4 years

    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?

    • Franklin Yu
      Franklin Yu about 5 years
      “getting out of nested loops” is a common need in many programming languages. Besides the goto in C/C++ as @docwhat has mentioned, Java has labeled break and continue. (Python also has a rejected proposal for this.)
  • Denis de Bernardy
    Denis de Bernardy almost 13 years
    Curious to know... Reading this from an iPad, so can't test them in 1.9, but some of those gotchas are no longer valid in recent ruby versions, right?
  • docwhat
    docwhat over 12 years
    Also worth knowing: raise is very expensive. throw is not. Think of throw as using goto to get out of a loop.
  • docwhat
    docwhat over 12 years
    @Denis Which gotchas are you referring to?
  • hrdwdmrbl
    hrdwdmrbl about 11 years
    Avdi does not look like he sounds in podcasts.
  • Dennis
    Dennis over 9 years
    The Ruby Learning link doesn't seem to work. Here's another blog post that discusses the differences: danielchangnyc.github.io/blog/2013/10/23/throw-raise
  • Jared Beck
    Jared Beck over 9 years
    Funny, rubylearning.com thinks that Avdi's article is still there. I guess that's why we copy stuff over to SO, so it won't be lost!
  • wired00
    wired00 over 8 years
    Good explanation but begs the question, why on earth would they design raise in ruby = throw in other language. and then also include throw but it != throw in other languages. I can't see their original logic there
  • Mark Amery
    Mark Amery over 8 years
    @wired00 (Shrug.) I agree that it seems pretty eccentric compared to other popular languages today.
  • Jörg W Mittag
    Jörg W Mittag almost 6 years
    @wired00: It has been called "raising" an exception ever since the very first experiments with structured error handling in the 1960s, it is called "raising" an exception in the seminal articles that invented the modern form of exception handling, it is called "raising" an exception in Lisps and Smalltalks, which were some of the main inspirations for Ruby, and it is called "raising" an exception or "raising" an interrupt in hardware, where the concept existed even before the concept of a "programming language" existed. The question should rather be: why did those other languages change that?
  • Jörg W Mittag
    Jörg W Mittag almost 6 years
    @MarkAmery: Remember that many of those "other popular languages" are younger than Ruby or at least contemporary. So, the question should rather be: why did those other languages not follow Ruby (and Smalltalk and Lisp and hardware and the literature).
  • Mark Amery
    Mark Amery almost 6 years
    @JörgWMittag Interesting - you inspired me to do a little historical research. C++ had the notion of "throwing" an exception years before Ruby came along, and per english.stackexchange.com/a/449209/73974 the term actually goes back to the 70s... so I think we still get to criticise Ruby for taking established terminology and using it to mean something completely different.
  • morhook
    morhook over 5 years
    The link is broken!
  • Franklin Yu
    Franklin Yu about 5 years
    See ruby catch-throw and efficiency to understand more about the performance difference.