Bug #12984
closed`rescue *[]` should be equivalent to `rescue` as `method_call(*[])` is equivalent to `method_call`
Description
Splatting an empty array to a construct that takes a list is supposed to be equivalent to specifying no list
def foo
end
foo *[] #works
So rescue *[]
should be equivalent to rescue
begin
raise 'error' #Uncaught exception
rescue *[]
puts 'caught'
end
Updated by nobu (Nobuyoshi Nakada) almost 8 years ago
It's similar to:
super(*[])
Updated by bughit (bug hit) almost 8 years ago
Nobuyoshi Nakada wrote:
It's similar to:
super(*[])
I guess there's some similarity. But super has a very explicit definition. Only a naked super is auto-forwarding, any attempt to pass args turns it into manual super. So super(*[])
is equivalent to super()
, which makes sense, because by doing super(*array)
you are clearly trying to call explicit super.
Updated by bughit (bug hit) almost 8 years ago
bug hit wrote:
Nobuyoshi Nakada wrote:
It's similar to:
super(*[])
I guess there's some similarity. But super has a very explicit definition. Only a naked super is auto-forwarding, any attempt to pass args turns it into manual super. So
super(*[])
is equivalent tosuper()
, which makes sense, because by doingsuper(*array)
you are clearly trying to call explicit super.
The difference between rescue and super is that there is such a thing as an explicit empty super()
that passes nothing, but there is no corresponding explicit empty rescue()
that rescues nothing, and so rescue *[] manifests something that isn't supposed to exist.
Updated by jeremyevans0 (Jeremy Evans) over 5 years ago
- Status changed from Open to Closed
This is the expected behavior. rescue *array
should mean rescue only exception classes in the array. It should not mean rescue only exception classes in the array, unless the array is empty, in which case rescue StandardError. Otherwise you end up changing the meaning of things like:
exceptions=[]
exceptions << ArgumentError if ENV["ArgumentError"]
begin
raise ArgumentError, "x"
rescue *exceptions
puts "caught"
end
Updated by bughit (bug hit) about 5 years ago
- Status changed from Closed to Feedback
I stopped getting email notifications from bugs.ruby-lang.org, to whom should I report this?
I am going to reopen this because I did not have a chance to address your comment. And I made an argument that so far has not been addressed.
It should not mean rescue only exception classes in the array, unless the array is empty
That's not consistent with the meaning of splatting an empty array, whereas the opposite is.
In a construct that takes a coma separated list, splatting an empty array produces a void list (no values)
so rescue *[Class1, Class2]
translates to rescue Class1, Class2
rescue *[Class1]
translates to rescue Class1
and rescue *[]
to a plain rescue
which does not mean rescue nothing
That would be logical and consistent.
There is no explicit syntax for rescue nothing which would be something like rescue()
, so rescue *[]
has to mean rescue
and not the non-existent rescue()
Updated by jeremyevans0 (Jeremy Evans) about 5 years ago
- Status changed from Feedback to Assigned
- Assignee set to matz (Yukihiro Matsumoto)
bughit (bug hit) wrote:
I stopped getting email notifications from bugs.ruby-lang.org, to whom should I report this?
I'm not sure.
I am going to reopen this because I did not have a chance to address your comment. And I made an argument that so far has not been addressed.
Your argument is basically that rescue *[]
should mean rescue
. In reality, rescue
is a shortcut for rescue *[StandardError]
. If you look at it from that perspective, it is obvious that rescue *[]
and rescue *[StandardError]
should not be the same thing.
It should not mean rescue only exception classes in the array, unless the array is empty
That's not consistent with the meaning of splatting an empty array, whereas the opposite is.
In a construct that takes a coma separated list, splatting an empty array produces a void list (no values)
so
rescue *[Class1, Class2]
translates torescue Class1, Class2
rescue *[Class1]
translates torescue Class1
andrescue *[]
to a plainrescue
which does not mean rescue nothingThat would be logical and consistent.
There is no explicit syntax for rescue nothing which would be something like
rescue()
, sorescue *[]
has to meanrescue
and not the non-existentrescue()
The explicit syntax for rescue nothing is rescue *[]
:) . As I showed in my earlier example, changing rescue *array
to mean rescue StandardError
if the array is empty will break backwards compatibility.
Assigning to matz to make a decision on this.
Updated by bughit (bug hit) about 5 years ago
The explicit syntax for rescue nothing is rescue *[] :)
Splat is not part of the rescue syntax, it composes with it, the same way it composes with other constructs that take a comma separated list (invocations, not sure if there are others).
Here's an excerpt from "The ruby programming language"
Here’s how we would write a rescue clause to handle exceptions of either
of these types and assign the exception object to the variable error:
rescue ArgumentError, TypeError => error
Here, finally, we see the syntax of the rescue clause at its most general. The rescue
keyword is followed by zero or more comma-separated expressions, each of which must
evaluate to a class object that represents the Expression class or a subclass. These
expressions are optionally followed by => and a variable name.
It documents the specific synax of rescue but does not even mention the splat, which does not have any special meaning in this context and its general meaning is *[] == a void list
, so rescue *[] == rescue
Updated by Eregon (Benoit Daloze) about 5 years ago
The core of this is that rescue
(which means rescue StandardError) vs rescue *classes
(which means rescue any of classes
) is detected at parse time, not at runtime.
I think the current logic makes sense in that regard, and I think it's is less surprising than rescue *no_classes
to "magically" rescue StandardError
.
Updated by bughit (bug hit) about 5 years ago
I think it's is less surprising than rescue *no_classes to "magically" rescue StandardError
It is the current behavior that's magical. If you try to deduce what rescue *[]
means from the primitives, it goes like this:
-
*[]
means a void (non-existent) list - therefore
rescue *[]
meansrescue
. It can't meanrescue()
(likesuper()
) becauserescue()
does not exist
Anything but the above is special-casing, i.e. magic
Updated by matz (Yukihiro Matsumoto) about 5 years ago
- Status changed from Assigned to Closed
This *[]
is not just exception list omitted, but explicitly specifies zero exceptions to catch.
Thus the current behavior is intended.
Matz.