I don't KISS, but I like to keep it DRY.

If you didn't get past the disgusting interpretation of that title, then you probably shouldn't be reading this blog ;)
I make elephants out flies and flies out of elephants, after-all, the human genetic code is 40% bananas!

Monday, January 25, 2010

do{}finally{}

So I was minding my own business writing a simple patching(merging) tool for a certain XML format and came across a certain aspect that surprised me. Take a look at this code-snippet:
if comment.text.startswith('[/'+name+']'):      
      siblings.remove(comment)
      return
else:
      siblings.remove(comment)
      return self.removesequence(siblings, name)
The function itself is a part of the removesequence, which hence is a recursive function that removes certain elements from a list, including the outer bound of that slice to be removed. The system is akin to HTML. Suppose we have a series of nodes to be merged across several XML files, the beginning node gets a [tag] and the closing node gets a [/tag] attribute. Then we merge by deleting the nodes in between, and including, the bounding nodes, and then inserting the new nodes(with the new bounding nodes) in the exact same spot where the node with the attribute [tag] once stood.

Never-the-less, the point of this code is beyond the scope of this post! The idea is simple, it's that I have to remove the element in scope(comment) in either outcome of the boolean expression, however, what is in question is whether to continue to the next node or to stop at this one. Clearly I cannot delete the code before the boolean expression, rendering it invalid, so the only real choice I have is to repeat myself, now isn't that a bugger!

There are of course ways around this, but they're not too pretty, such as cloning the comment.text string(or well, that's probably as pretty as it gets), or adding a conditional immediate return at the top of the method, such that if it got None values it would return, resulting in an extra function call and more code!

This code-snippet reminds me of the reasoning behind the finally clause in a regular try-catch block in both C#, Java, and a few other languages. Thus the immediate idea is to introduce a type of if-then-else-finally block, however why stop there? Why not just abstract the finally concept into something by itself. I mean, the Java language prioritizes finally over return already, however, the question remains why this is solely a luxury for the anyways ludicrous try-catch blocks?

So, what about a do{}finally{}?

Updated
Scratch that, my bad, and I am somewhat ashamed of myself, this Java doc states the following:

"But finally is useful for more than just exception handling — it allows the programmer to avoid having cleanup code accidentally bypassed by a return, continue, or break. Putting cleanup code in a finally block is always a good practice, even when no exceptions are anticipated."

So the concept is certainly there and it's called a try{}finally{} in Java. Question then remains whether the unpleasant overhead of a try-catch is spared. As far as I can see from this blog post by Alan Keefer, it isn't.

Also, this python doc tells me the equivalent is also true for python:

"The try statement specifies exception handlers and/or cleanup code for a group of statements"

Thus, I can reorganize the aforementioned code-snippet as follows:
try:
   if comment.text.startswith('[/'+name+']'):      
      return
   else:
      return self.removesequence(siblings, name)
finally:
   siblings.remove(comment)

No comments:

Post a Comment