Monday, March 21, 2005

Try-finally: an addition

Um, one addition to the last post: the "create my own transaction if I'm not already under one" code fits into another already mentioned category, the contexts. A transaction is naturally a contextual property, it doesn't need to be passed down object or caller hierarchy. The under_transaction generator (or template, or macro, call it whatever you like :)) should really put its newly created Transaction object into a contextual variable, thus automatically making it available to any code that needs it.

And another thing, before things started sounding simple: an intelligent code generator could be able to detect what's going on in the rest of the code. In the example with the transaction, we had

under_transaction
{
// some code
}

It would be good if the code generator could be aware of the parts of "some code" that would really be using its transaction. It could then wrap its code more tightly around it.

How could it do this? With refactoring. But not the refactoring we know today - machines would really need simpler refactorings, something we humans wouldn't even call refactorings. Like, tightening a try-finally block. (Yes, I know, this is what optimizers routinely do. Note that I didn't say the code generator should do its own refactoring/optimization :)). But, more on that later.

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?).

Thursday, March 17, 2005

The solution

There's one "universal" solution Microsoft has given us and it may well be the only solution for our trouble with them: restart the universe and see if the problem repeats itself.

Friday, March 04, 2005

SP1 for Visual Studio 2002

I must say I never expected it to happen: Microsoft has released service pack 1 for Visual Studio 2002. Why now? What's the point? I thought Visual Studio 2003 was an (admittedly rather expensive) sp1 for visual studio 2002, since it brought us nothing new but bugfixes. So, when can we expect a service pack for Visual Studio 2003, in 2006?

Wednesday, March 02, 2005

Contextual / Ambient support

Wouldn't it be nice if we had context support built into programming languages? Oftenly when you write code you have some object "X" that is almost global but not quite. You want all the calls from one point onward to use this value, but you can't make it static so you end up bouncing it around as an additional argument in all method calls. Like this:

method1()
{
X = something;
method2(a, b, c, X)
}

...

method5(r,X)
{
y = X.property
}

It would be much nicer to be able to set "X" as a contextual value in method1. A callee method could have a way to detect the closest parent context containing the value it needs, and get it. Like this:

method1()
{
X = something;
context.contextualX = X;
method2(a,b,c);
}

...

method5(r)
{
y = context.contextualX;
}

Here, the line
y = context.contextualX
would mean "find the closest context that has 'contextualX' defined and return that value". This would also mean that some method3 could override this value and set its own for its own callees to consume.

Ok, so this is something AOP guys already have (say, in AspectJ, although slightly different). But there is another aspect (pun intended) here: what about structural hierarchy? How do I make all child controls inherit their background color from the parent (windows programmers call this an "ambient" property)? This should be done in a similar way. Obviously, someone would have to tell the runtime that in this case control hiearchy is established using the Parent property found in the Control class, but that's all. Moreover, if we can do this, we can have multiple hierarchy types using different properties. So, to summarize, let's say we declare different context types, like this:

// a structural context using the Control.Parent property
context MyControlContext : StructuralContext <"Control.Parent">
{
int BackgroundColor;
}

// a call context
context MyCallerContext : CallContext
{
int contextualX;
}

We would use these properties as if they were static, and the framework would take care of finding and storing their values. So:

MyControlContext.BackgroundColor = this.BackgroundColor;
...
inheritedBackground = MyControlContext.BackgroundColor;

or

MyCallerContext.contextualX = somevalue;
...
y = MyCallerContext.contextualX;

Now, I suppose that this could be implemented in C# using attributes and reflection (probably in a similar fashion, too, in Java). But it would be painfully slow and ugly. What is needed is built-in support in the runtime. One day, maybe?