Feature #10042

Deprecate postfix rescue syntax for removal in 3.0

Added by Charles Nutter 8 months ago. Updated 5 months ago.

[ruby-core:63754]
Status:Open
Priority:Normal
Assignee:Yukihiro Matsumoto

Description

The postfix rescue notation is convenient...but almost always is a really bad antipattern.

An example of the notation:

Integer(f) rescue f # returns f if it is not parseable as an Integer

It silently ignores all StandardError raised by a piece of code...which often covers many more exceptions than the user wants to be ignoring.

It also hides the cost of constructing and throwing away all those ignored exceptions.

I believe Matz has even said in the past that he regrets adding the feature.

In any case, I propose that "rescue nil" should be deprecated with a warning (either always on or only when verbose) and we should plan to remove it in 3.0.

Who's with me?!

History

#1 Updated by So Wieso 8 months ago

Hi, I'm against it :-)
Nobody is forced to use it, and for short scripts it can be quite useful.
For example to fetch some websites, if they exist:

require 'open-uri'
urls = …
urls.each do |url|
  open(url) do
    #save the file
  end rescue nil
end

But it would be ok for me if we need to specify the Exception.

#2 Updated by Yui NARUSE 8 months ago

I sometimes use postfix rescue, and often want a new syntax to specify exceptions to rescue.

#3 Updated by Matthew Kerwin 8 months ago

On 26/07/2014, naruse@airemix.jp naruse@airemix.jp wrote:

Issue #10042 has been updated by Yui NARUSE.

I sometimes use postfix rescue, and often want a new syntax to specify
exceptions to rescue.

This was a feature of MOO Code, on which I cut my teeth in the 90s. It
lead me to create the 'try' gem. I would not be disappointed if the
gem was made obsolete by a new language feature.

--
Matthew Kerwin
http://matthew.kerwin.net.au/

#4 Updated by Nobuyoshi Nakada 8 months ago

  • Tracker changed from Bug to Feature

#5 Updated by Boris Stitnicky 6 months ago

Nooo! Don't remove tail rescue! I suggested to introduce tail "resc" keyword with exception to be rescued somewhere here.

#6 Updated by Boris Stitnicky 6 months ago

Got it, this is what I proposed:

do_messy_job resc TypeError: 42, NameError: 43

#7 Updated by Charles Nutter 5 months ago

The problem is that postfix rescue is almost always used incorrectly, ending up swallowing 99% of errors that Ruby programs raise. It also masks the very high cost of creating an exception and backtrace (high on MRI, higher on Rubinius, and very high on JRuby/JVM). Finding these bugs (or performance hits) can be very difficult.

I believe the potential for serious bugs outweighs the convenience of this syntax.

#8 Updated by Charles Nutter 5 months ago

At the very least, we should introduce a syntax for rescuing a specific exception type, and warn when users don't use that syntax. The syntax proposed by Boris isn't too bad.

I wonder if there's a way we could make postfix rescue turn off backtraces downstream. If downstream code passes through another rescue, the optimization would be turned off because that rescue might want the trace.

#9 Updated by Yukihiro Matsumoto 5 months ago

  • Assignee set to Yukihiro Matsumoto
  • Target version changed from next minor to Next Major

Hedius, separate your concern, performance and language design.

I haven't seen any "serious" problem caused by exceptions swallowed by postfix "rescue". So I don't worry too much about the issue.

Of course specifying exception class reduce chance for misbehavior, so if some one come up with nice idea, I'd love to merge and encourage it. But adding new reserved word is unacceptable. Any idea?

I don't care much about the performance here. Adding new syntax won't solve the issue.
We can just discourage use of exceptions in tight loops in the documentations.

Matz.

#10 Updated by Recursive Madman 5 months ago

An alternative syntax that doesn't introduce a new reserved word would be:

do_something_messy rescue(TypeError, NameError) do_something_with($!)

The syntax within the parentheses could be the same as after a block rescue, e.g.:

do_a rescue(SomeError => e) do_b(e)

This doesn't introduce a new reserved word and causes a syntax error on older ruby versions (thus preventing existing code from suddenly working differently).

#11 Updated by Nobuyoshi Nakada 5 months ago

Recursive Madman wrote:

An alternative syntax that doesn't introduce a new reserved word would be:

do_something_messy rescue(TypeError, NameError) do_something_with($!)

It conflicts with existing code for single exception class.

I thought a syntax like rescue < exception, but can't fix conflicts yet.

#12 Updated by Recursive Madman 5 months ago

Nobuyoshi Nakada wrote:

Recursive Madman wrote:

An alternative syntax that doesn't introduce a new reserved word would be:

do_something_messy rescue(TypeError, NameError) do_something_with($!)

It conflicts with existing code for single exception class.

Could you provide an example?

#13 Updated by Nobuyoshi Nakada 5 months ago

Currently,

do_something_messy rescue(TypeError)

is valid code, and TypeError is a expression to be returned when an exception raised.

With your proposal, it becomes an exception class to be rescued.
That means the meaning of that parenthesized part changes by if it has succeeding expression.
It would result just another confusion, IMHO.

And I'm afraid that it might not be able to parse correctly.

#14 Updated by Recursive Madman 5 months ago

I see how it would conflict when both forms (do_a rescue(TypeError) and do_a rescue(TypeError) do_b) are supported (the parser can't decide between recognizing parenthesized exceptions or stmt), but when the former form (i.e. not specifying an exception) is no longer allowed, do_a rescue(TypeError) becomes invalid code.

#15 Updated by Avdi Grimm 5 months ago

On Mon, Nov 10, 2014 at 10:25 PM, matz@ruby-lang.org wrote:

I haven't seen any "serious" problem caused by exceptions swallowed by
postfix "rescue". So I don't worry too much about the issue.

I won't claim that writing a book on Ruby exceptions makes me an expert.
But at least I've made a special study of them for the past decade or so of
Ruby use, and over numerous large-scale client projects. Of bugs that could
be traced to use of a language feature, postfix rescue is easily in the top
three. In fact, offhand I'm not sure I can think of any language feature
whose use has led directly to more problems than this one. Unless you count
"the existence of nil" as a language feature ;-)

Postfix rescue bugs are especially insidious, because they usually hide
other bugs.

Can you accidentally throw away exceptions without it? Sure. But other
methods are more visually obvious. Postfix rescue hides out at the ends of
long lines in legacy codebases, quietly breaking things.

The abuse of postfix rescue is so bad in Ruby projects that at this point I
consider only one usage of it acceptable: rescue $! for converting
exceptions to returns. I flag any other usage as an error, because if it
isn't causing problems already, it almost certainly will eventually.

I would like to see some equivalent of rescue $! stay in the language,
but other than that I'd be more than happy to see it leave the building
entirely.

--
Avdi Grimm
http://avdi.org

Also available in: Atom PDF