Project

General

Profile

Feature #15936

on_error in lieu of rescue, raise

Added by kylemacey (Kyle Macey) 4 months ago. Updated 4 months ago.

Status:
Open
Priority:
Normal
Assignee:
-
Target version:
-
[ruby-core:93304]

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)

History

Updated by shevegen (Robert A. Heiler) 4 months 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) 4 months 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) 4 months 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) 4 months 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) 4 months 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) 4 months 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 the rescue 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.

Also available in: Atom PDF