Monday, March 21, 2005

Example: generating try-finally wraparound code

Here's a nice illustration of the kind of work the before-mentioned code generators could do for us. Consider the following pseudo-C#, where an operation is done under a transaction, and wrapped within a try-finally block:
this.Transaction = new Transaction();
bool success = false;

try
{
// do something under Transaction
// ...
success = true;
}
finally
{
if(success)
Transaction.Commit();
else
Transaction.Rollback();
}

What we have here is a good example of unavoidable repeated code. Anywhere you want to do several operations under one transaction, you're bound to repeat this. You cannot extract the common code and put it into a method, because your non-common code is in the middle of it. You cannot make two methods (beginning and end) because you cannot split the try-finally block. You're bound to repeat it, over and over again.

Now, the above code is not too big or complicated, and one could live with repeating it. But, we could make it more complicated by having the method create its own transaction if it isn't already under one. Something like this:

bool usingLocalTransaction = false;

if(this.Transaction == null)
{
this.Transaction = new Transaction();
usingLocalTransaction = true;
}

bool success = false;

try
{
// do something under Transaction
// ...
success = true;
}
finally
{
if(usingLocalTransaction)
{
if(success)
Transaction.Commit();
else
Transaction.Rollback();
}
}

Now, this is just a hint of how ugly it can get - and there is no easy way out. The modern programming paradigms (at least the ones I know of) don't give us a solution here.

So, we'll call our fictional code generators to the rescue. The code above would look like:

under_transaction do
{
// do something under Transaction
// ...
}

The code generator for under_transaction could be an absolute simpleton: its task would be simply to replace the given code block's begining and end with its own transaction-management code. (The IDE/compiler would possibly have to mangle some of the variable names to avoid duplicates).

Do we really need a code generator to solve this particular problem? Probably not - we could walk away with changing the way methods are defined (there wouldn't just the methods that you need to call, but new kind of methods that somehow wrap around your code). But this change would be more easily done with a code generator. We could write a "wraparound-inline-method" generator for this occasion. We could invent other ways to do the same thing, write generators and suit our needs any way we want to (invent our own dialect of a programming language? Why not?).

No comments: