Feature #15936
openon_error in lieu of rescue, raise
Description
A common bad pattern in ruby is to rescue any exception and accidentally clobber the exception.
begin
some_method
rescue StandardError
#
end
Most linters will complain if you write rescues like the code above. However, this could be useful if we want to perform an operation on any error, as long as we re-raise the exception after doing our work.
begin
some_method
rescue StandardError
job.fail!
raise
end
Here, though, we run the risk of potentially forgetting to reraise the exception, or having to make exceptions in our linter for an operation that is overall benign.
What would be a thought on using another keyword that doesn't actually rescue an exception, but performs an operation in the event of an error? Similar to ensure
, but only in the event of an error.
begin
some_method
on_error StandardError
job.fail!
end
(obviously, someone more creative than me should come up with a better name)
Updated by shevegen (Robert A. Heiler) over 5 years ago
Hmmm.
I have not made up my mind so I can not even say whether this may be interesting
or not.
But I think just a few general thoughts:
-
People may expect begin/rescue/end, more than any alternatives. They may wonder
what on_error is or how it would be used (or any other name). -
Is it very common to use ensure/rescue/re-raise? I have no statistical data but
in my own code, but also in code by other people, it seems as if simple begin
rescue clauses are highly prevalent. This should not be assumed as a con opinion,
I am just pointing this out in context as to whether on_error would be worth
to be added (and I honestly do not know).
As for potentially pro-points, if I understood one part of your issue correctly
then you also suggest being able to handle a specific error-case with this
line exactly. Or at the least this is how I understand the code example, where
in the second you can omit one line right?
These are just some semi-random comments from me - as I wrote above, I really
do not even have the slightest idea yet whether I may like, dislike or even
just be neutral on it. :)
Updated by kylemacey (Kyle Macey) over 5 years ago
shevegen (Robert A. Heiler) wrote:
Hmmm.
I have not made up my mind so I can not even say whether this may be interesting
or not.But I think just a few general thoughts:
- People may expect begin/rescue/end, more than any alternatives. They may wonder
what on_error is or how it would be used (or any other name).
Yeah, this is a proposal to extend the available keywords in ruby core. So ideally, there would be release notes and documentation that would help guide people to this new feature.
- Is it very common to use ensure/rescue/re-raise? I have no statistical data but
in my own code, but also in code by other people, it seems as if simple begin
rescue clauses are highly prevalent. This should not be assumed as a con opinion,
I am just pointing this out in context as to whether on_error would be worth
to be added (and I honestly do not know).
This is coming from a need that I personally face often on the utilities I work on, where I need to update state on an object if something unexpected happens. My company's linter gets upset when I use the rescue StandardError
pattern, so I was hoping to have a way to be more explicit that I'm not trying to prevent the error from going up the stack, I just want to act upon the exception.
As for potentially pro-points, if I understood one part of your issue correctly
then you also suggest being able to handle a specific error-case with this
line exactly. Or at the least this is how I understand the code example, where
in the second you can omit one line right?
Yeah, there's the nicety of being able to reduce a line, but even more enticing is how explicit this pattern feels, and how it can be less error-prone (by forgetting to reraise, or by accidentally casting too wide of a rescue
net).
These are just some semi-random comments from me - as I wrote above, I really
do not even have the slightest idea yet whether I may like, dislike or even
just be neutral on it. :)
Updated by jeremyevans0 (Jeremy Evans) over 5 years ago
kylemacey (Kyle Macey) wrote:
What would be a thought on using another keyword that doesn't actually rescue an exception, but performs an operation in the event of an error? Similar to
ensure
, but only in the event of an error.begin some_method on_error StandardError job.fail! end
Thankfully, Ruby already supports what you want:
begin
some_method
ensure
job.fail! if $! # or use case $! if you want to handle specific exception classes differently
end
As you can already accomplish this with current Ruby syntax, I do not think adding a keyword for it is warranted.
Updated by duerst (Martin Dürst) over 5 years ago
kylemacey (Kyle Macey) wrote:
This is coming from a need that I personally face often on the utilities I work on, where I need to update state on an object if something unexpected happens. My company's linter gets upset when I use the
rescue StandardError
pattern, so I was hoping to have a way to be more explicit that I'm not trying to prevent the error from going up the stack, I just want to act upon the exception.
What about getting the linter to recognize that you are using raise
again in the rescue
clause? That shouldn't be too difficult, at least for the simple cases.
Updated by kylemacey (Kyle Macey) over 5 years ago
jeremyevans0 (Jeremy Evans) wrote:
kylemacey (Kyle Macey) wrote:
What would be a thought on using another keyword that doesn't actually rescue an exception, but performs an operation in the event of an error? Similar to
ensure
, but only in the event of an error.begin some_method on_error StandardError job.fail! end
Thankfully, Ruby already supports what you want:
begin some_method ensure job.fail! if $! # or use case $! if you want to handle specific exception classes differently end
As you can already accomplish this with current Ruby syntax, I do not think adding a keyword for it is warranted.
ensure
fires even if there is no exception. This keyword would only fire when there is an exception. In your example, job.fail!
would always be called.
Edit: Sorry, I missed the conditional, which lends my point that this code isn't as intentional.
Updated by kylemacey (Kyle Macey) over 5 years ago
duerst (Martin Dürst) wrote:
kylemacey (Kyle Macey) wrote:
This is coming from a need that I personally face often on the utilities I work on, where I need to update state on an object if something unexpected happens. My company's linter gets upset when I use the
rescue StandardError
pattern, so I was hoping to have a way to be more explicit that I'm not trying to prevent the error from going up the stack, I just want to act upon the exception.What about getting the linter to recognize that you are using
raise
again in therescue
clause? That shouldn't be too difficult, at least for the simple cases.
Very true! I can certainly do that, I just thought this might have the added benefit of writing more explicit and intentional code, and would eliminate the need to re-raise the exception.