Ruby wish list item: more standard rescues

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

···

--
Posted via http://www.ruby-forum.com/.

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

···

--
Posted via http://www.ruby-forum.com/\.

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.

···

--
Posted via http://www.ruby-forum.com/.

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=1698&aid=21239&group_id=426

···

--
Posted via http://www.ruby-forum.com/\.