Aspects And Meta Objects

I recently asked the question on the AspectJ mailing list: Is it better to learn the Common Lisp Object System to do aspects or to use AspectJ?

I received a reply from a guy named Gregor Kiczales ( :) ): AspectJ. There are several things necessary for AOP that CLOS just doesn't have. (This can be checked on the AspectJ mailing list archive.) If CLOS can't handle it, then I doubt Ruby can. -- Thaddeus Olczyk

I actually grasped AOP recently, once I read The Pragmatic Programmer. The last time I read the literature on AOP, they didn't have any good clear-cut examples of why AOP was good and how it was used.

I have a mental connection between AOP and Design By Contract. Am I just making abstract conceptual connections between two completely separate concepts because I don't quite understand everything yet, or did I just make sense?

I used to have that same "mental connection" but I think that the former is the case. DBC is more about specifying interfaces to classes, whereas AOP is a different paradigm than OO.

When you can not use the PROGRAMMING LANGUAGE to express your use case OAOO. use the tool AOP.

The Voice Of Ignorance asks: isn't this just multiple inheritance and before and after methods for a language which doesn't have them? It just seems like AspectJ wants to add a Meta Object Protocol to Java.

An even more IgnorantVoice replies: I heard that the author of the Meta Object Protocol learned from his mistakes, and turned to AOP. This is second-hand, so caveat wikitor.

A Meta Object Protocol (MOP) is a way to implement AOP. That is, AOP puts structure and expressiveness onto the raw power of the MOP. Consider the parallels with Structured Programming: one can implement any algorithm using conditional goto statements as the only control structure but it's easy to shoot oneself in the foot and the resulting code is hard to read. Therefore modern languages provide control structures that enforce structured programming techniques. Similarly a MOP provides powerful hooks into the underlying object model but results in complex code and errors that are hard to debug. AOP provides declarative notations and tool support to generate functionality that is implemented through the MOP.

AOP as shown in AspectJ goes beyond CLOS-style BEFORE and AFTER methods. The AspectJ compiler does a syntactic analysis of the entire Java program source code, and can insert its code at any one of a number of points in the original source. This is useful for any policy that you can implement through side-effects (such as logging, synchronization, and all the other examples). On the other hand, it makes it impossible to tell, when looking at a single Java function, just what the hell will happen when you call that function. Some new aspect that your co-worker introduced may be quietly changing the behavior of your class. Note that in Common Lisp, you're likely to create new constructs like WITH-SYNCHRONIZATION or DEFUN-LOGGED (rather than use BEFORE or AFTER methods), and these make the special behavior explicit in the code, but still leave the special behavior code in a single place.

The Common Lisp MOP is not about BEFORE and AFTER methods; those are just the standard Method Combination. What the MOP lets you do is define new metaclasses, and new method combinations, which determine how, if, and in what order all effective methods are combined and applied. -- Alain Picard

Somebody tell me if this is an apt analogy:

(I say Lisp Macros instead of Meta Object Protocol because AOP seems primarily concerned with reducing duplication of code, while MOP is more about flexibility.)

It seems like a Lisp Macros solution to the crosscutting concern would be to wrap code in a macro (as mentioned above), and then insert that macro into every place where the functionality is desired. Aspect Oriented Programming would define the functionality and then define all the pointcuts where that functionality is required in one place. Similarly, Go To makes you write a block of code and then insert Go To statements everywhere it's called, while Come From would let you put a whole bunch of Come From statements before the block to indicate where it should be called.

I guess the tradeoff is centralization of concerns vs. ability to follow the code. The AOP solution lets you keep everything related in one place, but if it ever breaks anything, you'll have a tough time tracking down the bug. The macro solution makes you do more work to insert or remove the functionality, but once it's there, everything's explicit and you don't have to hunt all over the place for aspects that might be affecting the code. Maybe that's why the Eclipse AspectJ site recommends using aspects sparingly in production code.

It strikes me that way too, and reminds me of the similar issue with callbacks. Their value is obvious, most famously in GUIs, but if you don't have the overall register+callback architecture firmly in your head (for instance, if you're looking at an existing codebase for the first time), then this stuff is far harder to understand and debug than synchronous code where interactions are all listed linearly for you.

A similar issue arises with the paradigm of "put code in databases, not files".

I think that such things really cry out for smart code browser support to allow multiple views of the code.

Is there an analogy with the development of the 'this' reference? To avoid constantly calling functions on the same data structure, we make the reference transparent by passing it implicitly to object methods and not requiring explicit use of it for their members. In a sense aspects are doing something equally humdrum, adding implicit calls to standardized abstract methods. But as with 'this', a simple idea can be very powerful. -- David Wright

I've looked at it, and I have some concerns. As a way of temporarily adding functionality this [AOP] is a powerful technique. As a way of adding permanent functionality it seems rather poor in that the changes to any code are implicit. It is not possible, without tool assistance or significant effort, to know which pieces of code are affected by some other distant piece of functionality.

I prefer my code to be explicit and local. I use wrappers. Low tech' but works just fine.

The Tool Command Language, especially along with the Extended Object Tcl, also lends itself neatly to this programming model and AOP is fairly frequently used. The ability to redefine commands dynamically, as well as pretty much everything else, provides a natural framework for which to build AOP methods. The Extended Object Tcl provides, in addition to classes and objects, the notion of method-filters which can be attached (dynamically, of course) to classes. These filters can capture calls and change them or redirect them. You also have the normal dynamic class-superclass and object-class relationships, as well as mixins.

There are various examples on the XOTcl page (www.xotcl.org ) of how these concepts can be used efficiently but here is one example from real life: I wanted to be able to cache results from a wide range of methods from different classes. I could've done it the traditional way and added caching to each class in concern but I chose to do it with method filters. I have a Memorization class which I can dynamically attach to any other. I can then specify which method results I want cached and how long they should be cached. It takes care of all of this automatically and the classes which do the actual work do not need to care at all about this (and neither do any of the callers). The Memorization class is completely generic and can be used with anything without anyone else knowing about it. Gave me a nice warm fuzzy feeling anyway.

-- Setok


See original on c2.com