ruby wish list item: more standard rescues

R

Roger Pack

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
 
B

Brian Candler

Roger said:
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
 
B

Brian Candler

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

Roger Pack

Brian said:
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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top