3

I'm trying to understand the syntax of Ruby-exceptions.

I found this example:

begin
    puts "Running with b=#{ b }"
    exception_if(b)
    puts "After possible exception"
  rescue ArgumentError => e
    puts "An error occured: #{ e }!"
  ensure
    puts "Always excuted, no matter what."
  end

Source: Wiki-Books

"ArgumentError" is the expection-type, which the rescue-branch shall catch? "e" is the reference-variable?

I'm I right there?

Then I found this snippet and that confused me then completely:

begin
  @product = Product.find(params[:id])
rescue => e
  redirect_to root_path
end

Where's the first part before the arrow (=>)?

Can someone explain me, how the two snippets are meant?

cluster1
  • 4,968
  • 6
  • 32
  • 49
  • 2
    You are correct that the first case will match any ``raise ArgumentError`` and ``e`` is the error, which allows you to get backtrace information, etc. In the second case ``rescue`` with no type will rescue ``StandardError``, which is the parent class of most 'normal' handlable application errors (not ``Exception`` as is the case in some other languages). – rmlockerd Aug 14 '20 at 05:50
  • Does this answer your question? [Why is it bad style to \`rescue Exception => e\` in Ruby?](https://stackoverflow.com/questions/10048173/why-is-it-bad-style-to-rescue-exception-e-in-ruby) – builder-7000 Aug 14 '20 at 06:15
  • 1
    @sergio Sorry, but it doesn't. My question was rather about the general syntax and it's feasible variations. It was mainly the different variations, which confused me. Nevertheless: Interesting read. Thanks for it. – cluster1 Aug 14 '20 at 09:46

2 Answers2

2

Edit: The second snippet is rescuing errors that are instances of StandardError, in a console:

begin
  raise NoMethodError
rescue => e
  puts e.inspect
end
#<NoMethodError: NoMethodError>

The exception object is assigned to the e variable. This can also read

rescue StandardError => e

The first snippet is initially rescue-ing one specific error, if another type of error is raised the ensure block will always be executed and then the method is exited.

As a general rule of thumb, you should only capture exceptions your program can recover from. If the program experiences an unknown exception crash it and fix the issue.

benjessop
  • 1,729
  • 1
  • 8
  • 14
2

Your interpretation of the first snippet is essentially correct. It's not 100% clear to me what you mean by "reference variable", though.

The identifier after the => arrow will be bound to the exception that was rescued, and is in scope within the rescue block.

The second snippet essentially just leaves out the exception class being rescued, which means it is using the default. If you don't specify the exception class, it will use StandardError as the default, and rescue from all exceptions that are instances of StandardError.

Note: this will not rescue all errors! It will only rescue exceptions that are instances of StandardError, but not all instances of Exception.

For example, SystemStackError directly inherits from Exception and is not a subclass of StandardError, and thus will not be rescued by your second snippet.

In general, exceptions that don't inherit from StandardError are ones that you cannot recover from anyway, such as running out of memory, or corruption of the internal data structures of the VM. You should strive to always specify the exceptions as narrowly as possible and only rescue exceptions that you actually can handle – ideally, you would create custom exception classes for your own code, and only rescue those.

Jörg W Mittag
  • 363,080
  • 75
  • 446
  • 653