Forum: Ruby ruby wish list item: more standard rescues

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Bec38d63650c8912b6ba9b557fb953b9?d=identicon&s=25 Roger Pack (rogerdpack)
on 2008-11-26 15:30
Currently in Ruby

begin
 ...
rescue
end

which I believe rescues different classes exceptions than

begin
 ...
rescue => e
end

and

begin
 ...
rescue Exception
end

which always surprises me.  Any preferences over always rescuing
Exception?
For example, Timeout::Error doesn't get caught.
Thanks!
-=R
753dcb78b3a3651127665da4bed3c782?d=identicon&s=25 Brian Candler (candlerb)
on 2008-11-26 15:58
Roger Pack wrote:
> which always surprises me.  Any preferences over always rescuing
> Exception?

It looks pretty consistent to me. The default is to catch StandardError,
and most "normal" errors are subclasses of this. Only gross system-level
errors are outside of this, and you probably didn't want to catch them
anyway.

There was talk of ruby-1.9 moving NoMethodError outside of StandardError
- or at least, (x rescue y) not catching it - but a test suggests that
hasn't been done.

Anyway, here's a program you can use to demonstrate how consistent it
is. If you can show something inconsistent, please update the code to
show it.

require 'timeout'

RAISERS = [
  ["timeout error", lambda { raise Timeout::Error }],
  ["bad method name", lambda { zxkjcnvkj }],
  ["divide by zero", lambda { 1/0 }],
  ["Exception", lambda { raise Exception }],
]

CATCHERS = [
  ["rescue blank", lambda { |r|
    begin
      r.call
    rescue
    end
  }],
  ["rescue => e", lambda { |r|
    begin
      r.call
    rescue => e
    end
  }],
  ["rescue StandardError", lambda { |r|
    begin
      r.call
    rescue StandardError
    end
  }],
  ["expr rescue expr", lambda { |r|
    r.call rescue nil
  }],
  ["rescue Exception", lambda { |r|
    begin
      r.call
    rescue Exception
    end
  }],
]

CATCHERS.each do |c|
  puts "*** For #{c.first}"
  RAISERS.each do |r|
    begin
      c[1].call(r[1])
    rescue Exception
      puts "   Didn't catch #{r[0]}"
    else
      puts "   Caught #{r[0]}"
    end
  end
end

$ ruby raiser.rb
*** For rescue blank
   Caught timeout error
   Caught bad method name
   Caught divide by zero
   Didn't catch Exception
*** For rescue => e
   Caught timeout error
   Caught bad method name
   Caught divide by zero
   Didn't catch Exception
*** For rescue StandardError
   Caught timeout error
   Caught bad method name
   Caught divide by zero
   Didn't catch Exception
*** For expr rescue expr
   Caught timeout error
   Caught bad method name
   Caught divide by zero
   Didn't catch Exception
*** For rescue Exception
   Caught timeout error
   Caught bad method name
   Caught divide by zero
   Caught Exception
753dcb78b3a3651127665da4bed3c782?d=identicon&s=25 Brian Candler (candlerb)
on 2008-11-26 16:05
There was a mistake there, the Timeout::Error line should say

  ["timeout error", lambda { raise Timeout::Error, "hello" }],

You're right that this isn't a subclass of StandardError and isn't
caught. It's a subclass of Interrupt. You can argue whether that was a
good design decision or not - but since a Timeout::Error means that a
thread was aborted mid-way at some arbitrary point, it's definitely an
unusual case.

There are plenty of posts about why the entire timeout library is broken
anyway.
Bec38d63650c8912b6ba9b557fb953b9?d=identicon&s=25 Roger Pack (rogerdpack)
on 2008-12-03 16:41
Brian Candler wrote:
> There was a mistake there, the Timeout::Error line should say
>
>   ["timeout error", lambda { raise Timeout::Error, "hello" }],
>
> You're right that this isn't a subclass of StandardError and isn't
> caught. It's a subclass of Interrupt. You can argue whether that was a
> good design decision or not - but since a Timeout::Error means that a
> thread was aborted mid-way at some arbitrary point, it's definitely an
> unusual case.
>
> There are plenty of posts about why the entire timeout library is broken
> anyway.

Yeah that one is the the kicker, and it is definitely broken.  Any
thoughts on making it descend from StandardError? [I want to propose it,
as some others do...]
Thanks!
-=R
http://rubyforge.org/tracker/?func=detail&atid=169...
This topic is locked and can not be replied to.