I have to agree with you on this one Bill (is the earth suddenly shaking really hard or is it just me?).
C++ and C macros are very, very simplistic simple text substitutions. I mean really simplistic. The C and C++ standards are written in such a way that:
- The macro processor can run as a stand alone literal preprocessor
- The macro processor has close to 0 knowledge of C or C++ syntax or semantics
When I say "close to 0 knowledge", what that means is that the preprocessor knows a couple of extremely primitive syntax points, but knows nothing about program structure, semantics, or even most of the syntax rules.
Even if you want to compare to a more sane macro system, it still doesn't hold. Macros are purposefully invoked within your source code. The entire point of AOP is quite different - to specifically _not_ include the aspect code.
A template argument likewise doesn't really hold, for the same reason as macros, unless the only point is to talk about complexity. And even there it's a murky analogy.
Macros are insidious not because of complexity, but because they're too simple, too dumb and literal minded. All of their problems stem from the fact that it's nothing more than literal text substitution.
C++ templates are insidious because the syntax is hideously deformed, and because the C++ template rules introduce very subtle semantics that catch even veteran C++ programmers. Using templates can be reasonably painless to an extent if they're very well fritten, but writing them is pretty much always a bear.
With AOP, the real problems are:
- It's not necesarily easy to know what a pointcut is going to match.
- As a corollary, when looking at a piece of code you may not be aware that a pointcut is active against it
- In most AOP systems it's so easy to write a pointcut that a certain class of people will be encouraged to go hog while and create an explosion of unnecessary pointcuts and aspects.
- Many AOP features are, by their nature, very facile at circumventing a pre-existing design. Intercepting calls in various means via pointcuts, introducing code via advice - these features can be used to hack new functionality onto a pre-existing design in a very, very ugly manner. Put another way AOP represents an easy out for many people - a substitute for a good design, if you will.
By my way of thinking, in the long term AOP will be a second-string player in the developer's playbook (how's that for subtly mixing metaphors :-). It will be very much like implementation inheritance - a very useful thing but not something to be overdone. It should not, in my opinion, be something as fundamental, pervasive, and used repeatedly like variables, methods, classes, and use of interfaces and interface inhertiance.
In my mind, the last bit is the real yardstick of a new technique or language feature - compare it to Java variables, methods, classes, interfaces, and how they are used (and explicitly excluding implementation inheritance aka extends). If a feature is as universally applicable to many coding problems as, say, an interface - or the lowly variable or method - then you're onto something. AOP doesn't meet that criteria, it's not (or perhaps I should say, should not) be as pervasive in use as classes and methods and variables and interfaces.
As a counterpoint, consider closures (in particular, closures a la groovy). Closures in my mind are right up there with variables and methods and classes and interfaces in their universal applicability. They could be widely used on a day-to-day coding basis by people. AOP in my mind doesn't reach that level of applicability. And attempts to reach that kind of applicability with it will lead to heartaches that outweigh the benefits.