begin + else
Posted by Jamis on February 08, 2007 @ 12:34 PM
Even after 6+ years, Ruby still continues to surprise and delight me. My latest discovery (thanks to Mauricio’s Happy 2007 challenge) is that begin/end blocks accept (in addition to rescue and ensure) an else clause:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
begin # main code here rescue SomeException # ... rescue AnotherException # .. else # stuff you want to happen AFTER the main code, # but BEFORE the ensure block, but only if there # were no exceptions raised. Note, too, that # exceptions raised here won't be rescued by the # rescue clauses above. ensure # stuff that should happen dead last, and # regardless of whether any exceptions were # raised or not. end |
If you don’t have an ensure clause, else is pretty much the same as just putting code immediately after the end, but if the order matters (something should happen before ensure, and only if the main code succeeded, and should not be subject to being rescued if something goes wrong), then else is your man.

1. Eric Anderson said...
I remember reading about this in the Pickaxe book back when I was first learning Ruby. I have never quite understood the need for this. Compare the following:
<macro:code> begin possibly_failable_action run_this_only_when_success rescue SomeException run_this_only_on_failure ensure run_this_no_matter_what end <macro:code>vs.
<macro:code> begin possibly_failable_action rescue SomeException run_this_only_on_failure else run_this_only_when_success ensure run_this_no_matter_what end <macro:code>These both should do the same thing but the first one gets by without the extra “else” construct. So that although it is neat and arguably more clear in it’s meaning I have always found myself doing the first method. Probably because other languages don’t have the nifty “else” construct so my mind seems to always be pushing me towards the first method.
2. Eric Anderson said...
Arg.. I guess I’m just going to give up on trying to use that nifty ruby formatting. :)
3. Jamis said...
The closing tags needs to be </macro:code>, and then it should work fine. (That’s probably my fault; there was a typo in my previous explanation of how this worked.)
4. Jamis said...
Eric, the difference between the former and the latter examples you gave is this: in the first, any exception in “run_this_only_when_success” will cause the rescue clause to be invoked, whereas when using the ‘else’, exceptions in the else clause are not rescued.
It’s a subtle difference, but I found a need for it today and saw the light. :)
5. ry said...
I had the exact same reaction as Eric. Of course, that is probably do to the way this is achieved in other languages that don’t have this construct.
I suppose the benefit of this is readability—the code that is evaluated only in event of success is explicitly denoted as a conditional block.
6. Kevin Smith said...
Eric, I may be misunderstanding the use of the else, but I think the key is that the code in the else part is not checked for exceptions. Any exception that happens will bubble up the call stack as normal. I can’t see a super good reason for this at the moment, but it is slightly different from your first code snippet.
7. Kevin Smith said...
Jamis, What was your use case?
8. Adam T. said...
It’s a matter of taste, definitely, but I prefer the latter for cleanliness (that is, why explicitly use the “begin” statement when it is done for you?).
9. Jamis said...
Beautiful, Adam, thanks for that example.
10. sri said...
I don’t think “else is pretty much the same as just putting code immediately after the end”, without the ensure clause.
Let’s say you catch an exception but ignore it. Then your else part won’t run. Whereas if the else part is after end, then it will still run.
isn’t the same as
11. Wes said...
I almost want to think of it as ‘sucess’ instead of ‘else’, because it’s run when there’s a lack of an exception.
12. Eric I. said...
But how is Adam’s example different from this?</>
13. Jamis said...
Eric, it’s not. The two are (semantically) identical, though Adam’s makes it clearer what happens when no exceptions are raised. Some might prefer it one way, some another. Ruby does, after all, follow the TIMTOWTDI philosophy.
14. Eric I. said...
I’m not sure that Ruby’s philosophy or set of goals explicitly includes TIMTOWTDI. Matz has said that Ruby follows good user interface design. And many have said that Ruby follows the Principle of Least Surprise. You can read a bit more on the Wikipedia section on Ruby’s philosophy.
As for what’s clearer, that tends to be personal. But when I read the block above the rescue blocks, I interpret that as what happens unless an exception occurs. I don’t think breaking that up and spreading that out helps all that much.