Ruby wish list item: more standard rescues


#1

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


#2

Roger P. 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


#3

Brian C. 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


#4

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.