There are a few things I'd like to understand in how Ruby treats inline Error handlers
Case 1
This is a common use case
def foo
raise Error
end
bar = foo rescue 1
# => 1
bar
# => 1
It works as expected. The expression foo rescue 1
returns 1
and it is correctly assigned to bar
.
Case 2
Ruby allows descructuring arrays, so this behavior seems odd.
baz = 'a'
baz, bar = foo rescue [1, 2]
# => [1, 2]
baz
# => 'a'
bar
# => nil
The expression returns the array [1, 2]
but doesn't deconstruct or assign it. It completely skips the assignment altogether.
Case 3
When you wrap the the error in parenthesis, however, the deconstruction works.
baz, bar = (foo rescue [1, 2])
# => [1, 2]
baz
# => 1
bar
# => 2
Case 4
Bonus points: Raising the Error and trying to handle it inline also skips assignment
baz = raise Error rescue 1
# => 1
baz
# => nil
But adding parenthesis makes it work.
Edit:
I tested this on Ruby 1.9.3-p392 and Ruby 2.0.0
Edit 2:
I added labels to cases
Edit 3:
Apparently some folks think this isn't a question, so maybe the title wasn't obvious enough. Here's the question in full text:
Why do these inconsistencies happen, and why does adding parenthesis change anything?
Your case 2 is the same as this:
baz = 'a'
(baz, bar = foo) rescue [1, 2]
Since foo
raises an error, assignment of values to baz
and bar
fails, so baz
remains to be "a"
, and bar
remains to be nil
, a value that was assigned during the parsing stage. Then, the assignment gets rescued, and the return value would be [1, 2]
.
Your case 4 is the same as this:
(baz = raise Error) rescue 1
Since the righthand side of the assignment raises an error, assignment to baz
fails, and baz
would remain to be nil
, that was assigned during the parsing stage. Then, the assignment is rescued, and the return value is 1
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With