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