Code Gen vs. AOP
Craig Andera seems to think that AOP is doomed as a programming model and Code Gen is the future. His basic argument is this:
"The basic problem here is that services are not generally orthogonal. What that means is that it’s impossible to simply slap a new behavior onto code without understanding all the other behaviors that are already there. Don’t believe me? Then ask yourself why the CLR’s context infrastructure has IsContextOK. This is the method that – when implementing a new service – lets you look around your environment and decide if you’re compatible with all the other services that are already present. This has two basic problems:
1. How do you know if you’re compatible with a given service that didn’t even exist when you were created?
2. What do you do if there’s a service that you’re not compatible with, but it doesn’t get added until after IsContextOK gets called? After all, the system has to call them in some order.
The mere fact that IsContextOK even exists is a dead giveaway that the whole thing is hopeless. If services were truly composable, we wouldn’t need it. Sure, some things like logging or security might work like this, but it just doesn’t generalize."
Clemens agrees with the problem, however, he disagrees on how fatal the flaw is:
"I don't think it fundamentally matters much how code gets woven into the call chain. Setting up contexts is just one issue. What's even more difficult is to find a way to deal with errors in the presence of cooperating aspects (or, in more general terms, interception services). What's clear is that there's no way around interception-driven services in a web services world. It's all pipeline-based and, even worse, the pipelines are distributed pipelines of pipelines. It's too simple to say "it's broken, get over it". That doesn't help solving what is an actual problem.
A promising approach is to make aspects/interceptors act like resource managers and coordinate their work using a very lightweight 2PC protocol ("AC" guarantee only; no "ID"). Using 2PC for this approach allows interceptors/aspects to coordinate their work and know about each other before any work actually gets done. I have discussed these issues with a couple of people in depth we put some code together that essentially implements a little, in-memory "DTC" for that purpose. We call it a "WorkSet" instead of a transaction. There's still some work to be done there, but I think I'll be able to post an example in a little while. Maybe around TechEd Europe time."
I have to agree with Clemens here. AOP is still very young, so it is understandable that it has a few major limitations. But, coordinating aspects is definately not impossible. With an attribute based AOP approach, determining all the available aspects / services at runtime could be as simple as examining the associated attributes of the method call via reflection. Then, you simply need to change your call model, so that it isn't just "Add Dumb Message Sink and Continue" (aka. IContributeObjectSink).
This is not to say that CodeGen is not a useful tool though. I am of the opinion that we need CodeGen support at the compiler level, not just the tool level before CodeGen will ever allow us to produce clean, managable code. Despite their obvious problems, you have to admit that elegantly written C++ macros could save a TON of coding. I know of at least two projects here that would have been far more difficult to develop without them (or at least for more difficult to maintain). We don't have anything similar in any of the .NET languages (not counting managed C++, of course), which is quite a shame. I could see how a more sophisticated code generation model (ie. running actual .NET code during compile time to do the CodeGen, instead of dumb macros), could really do some amazing things. It is a shame that a lot of language developers have given up on them, rather than address their obvious shortcomings, because there are many situations where method calls just don't cut it (ie. those situations where code generation is actually useful).