A layman’s take on aspect-orientated programming
Deprecated: preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead in /homepages/u37107/www.sebastian-kirsch.org/moebius/blog/wp-includes/functions-formatting.php on line 76
During my classes on software technology, we were also treated to a short introduction to aspect-oriented programming. Aspect-oriented programming is the latest trend1 in software engineering: It aims to implement separation of concerns not in different classes or object, but as different “aspects” of the same object. Typically, the cited uses are a “logging/debugging aspect", a “security aspect”2, a “persistence aspect” etc.
What’s an aspect? Twenty years ago, people were asking the same thing about object-oriented programming: What’s an object? As no coherent definition of an aspect has yet emerged, I will describe aspects by their most common implementation, AspectJ, a Java dialect. AspectJ introduces the concept of join point interception: at certain points in the program flow, additional code (the aspect) may introduced into the program. “Certain points” in this case are, basically, every method call. One may write a function (an aspect, also called “advice") that will be executed before certain method calls, after certain method calls, or even around certain method calls. This function will be executed in the context of the method call in question, receive all of its arguments, and may basically do what it wants. The methods to which an aspect may be applied can be specified using wildcards.
There is a workgroup for AOP and OOP at Bonn University that has developed an even more general aspect language called LogicAJ, as well as tools for transforming java source code and run-time interception of Java method calls.
Obviously, this is a very powerful technique. The first time I saw it, I said to the instructor, “We’ve been doing that in Perl for years, manipulating the symbol table of other modules and exchanging their subroutines for our own. And we always felt bad about it.”3 I was wary of it; it somehow went against my instincts. (That’s not to say I couldn’t become used to it; I also became used to function and operator overloading in C++.)
My reasoning was thus: I perceive a trend towards more and more structural and semantic clues in programming language, in order to help the programmer to provide better structure for his code. In LISP, we had functions and lists. That was it; LISP is one of the most syntax-free languages – but on the other hand, it allowed you to do everything, to program in any way you wanted. In Java, one of the most successful languages at the moment, we have a distinction between classes and interfaces, objects, object methods and variables, class methods and variables, static variables, final variables, subclasses and subinterfaces, etc. ad nauseam. Some languages provide specialized syntax for member initialization (for example C++), for choosing the appropriate function depending on the type of the argument (function overloading, in C++ or Java) or even according to the value of the argument (pattern matching, for example in the ML language.)
And now people are using this artificial structure to put a totally generic system on top of the language. Which, predictably, leads to problems. The application of aspects to a base program is euphemistically called “weaving” – which works all right and is understandable as long as you have only one aspect. But what happens when several aspects are applied to the same base program? How do they interact? In what order should they be executed? What if one aspect relies on functionality provided by a different aspect? Can an aspect be applied to another aspect (leading to a meta-aspect)? These problems are still unsolved. I doubt that it will ever be solved – the formal semantics of even the simplest imperative languages are thorny enough.
Slashdot picked up this problem in a recent article. The article is based on papers from Passau University that attack the soundness of aspect-oriented programming. They even go as far as titling one paper “Aspect-Oriented Programming Considered Harmful” (recalling Edsger Dijkstra’s seminal paper Go To Statement Considered Harmful”.) They state some of the problems of aspects much more succinctly than I could.
In a way, aspect-oriented programming is the antithesis to another trend in language design – functional programming. Functional programming tries to minimize or even remove side effects of code, specifying that a function with the same input data will always return the same data – regardless of the order in which function calls happen. Aspect-oriented programming does exactly the opposite – the whole purpose of an aspect is introducing side effects to existing code. One may argue which way is better – no side effects or all side effects.
Functional programming does have some advantages: for one, it is usually much easier to debug and to verify than imperative code (and, by extension, object-oriented and aspect-oriented code.) – owing to the fact that it’s virtually free of side effects. Some organizations that tried it reported a marked increase in programmer productivity; Ericsson springs to mind with the Erlang language. A good overview of the characteristics and advantages of functional languages in in the corresponding Wikipedia article.
As I said in the headline, I am just a layman in the field of programming language design. I am not particularly attached to a specific programming language, but I have seen lots of them. Why I just seem to perceive all their worst points, I don’t know; I guess I just have a critic in me.
Footnotes:
1It’s hard not to say “fad” instead of “trend".
2Whatever security actually is in this context.
3It turns out that there is actually a Perl module for aspect-oriented programming that does exactly that; in difference to Java, there is no need to change the Perl interpreter itself in order to implement aspect-oriented programming. The same is true for LISP, where aspects can be introduced using macros. In fact, LISP with its macro mechanism was the first language to introduce the idea of code as a “different kind of data” that can be manipulated by other code.