begin + else
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.
Reader Comments
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.
8 Feb 2007
Arg.. I guess I’m just going to give up on trying to use that nifty ruby formatting. :)
8 Feb 2007
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.)
8 Feb 2007
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. :)
8 Feb 2007
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.
8 Feb 2007
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.
8 Feb 2007
Jamis, What was your use case?
8 Feb 2007
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?).
8 Feb 2007
Beautiful, Adam, thanks for that example.
8 Feb 2007
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
8 Feb 2007
I almost want to think of it as ‘sucess’ instead of ‘else’, because it’s run when there’s a lack of an exception.
8 Feb 2007
But how is Adam’s example different from this?</>
9 Feb 2007
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.
9 Feb 2007
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.
10 Feb 2007