|
Fall 2002 Programming Language Seminar: |
|
Welcoming comments
Prerequisite: Java programming is very helpful, but C++ programmers can generally pick up Java fairly easy
There will be no exams or quizzes given in-class (and no substantial exam outside of class). The work of this class primarily will be focussed on the design and implementation of aspect-oriented AspectJ programs, with some smaller projects at the beginning and one or two larger assignments toward the middle or end of the semester. The course will chiefly deal with AspectJ, although there may be some mention of other systems for achieving similar ends as AspectJ, as well as other proposals aiming to meet the same benefits as Aspect-Oriented Programming.
Aspect-Oriented systems fall under the category of Advanced Separation of Concerns (ASoC). ASoC aims to allow the modular decomposition of software concerns that cross-cut the nature of an Object-Oriented program.
Concerns come in two general flavors, non-functional (or systemic) and functional. Non-functional concerns have to do with some aspect of the overall correctness of a program (for example: real-time requirements, thread synchronization, transaction semantics, caching/prefetching, memory management concerns, security, scheduling), while functional concerns correlate (roughly) to features of a program (for example: logging, encryption, additional supported network protocols) that may be included or excluded for a particular compile (or run) of the program. Note that functional concerns are somewhat like plugins in software -- a modular piece of code that is plugged in to achieve additional functionality. In software that supports plugins, however, the base code must acknowledge the existence of a plugin system and make calls out to it. With ASoC, the idea is to keep the core code and the plugins (and even the plugin system itself) completely independent.
Further, functional concerns can be configurational. In an Object-Oriented system, you may describe a particular organization's personnel hierarchy with an XML document, then parse and read it into an object at runtime. This object then typically either (1) resides as a Singleton, where it is accessed by all objects, or (2) is passed as an argument to the methods that require it as part of their computation. Unfortunately, this solution requires other objects to manipulate the personnel-hierarchy object in their code in order to carry out whatever requirements it asserts. This leads to an integration, rather than separation, of concerns. A truly modular approach would allow the configuration object independently to impose its requirements.
Ideally, then, all of our classes are totally abstract and totally independent. This isn't entirely possible, however (if there were absolutely no inter-object relationships, they couldn't form a cohesive program), but the points where code between different concerns gets tangled can be smoothed over if a separate aspect defines such relationships.
(Side note: This idea of a complete separation is at the core of Generative Programming, in which reusable components are built separately and then a "configuration" (in some form) is injected into the system to make them all behave together flexibly.)
Quantification and Obliviousness. Robert Filman and Daniel Friedman have observed that the key distinguishing feature of Aspect-Oriented Programming is that they exhibit quantification and obliviousness [Filman and Friedman, Aspect-Oriented Programming is Quantification and Obliviousness, available in PDF]. Quantification refers to the idea that one piece of code explicitly affects various other places in completely different sections of code; obliviousness (sometimes termed implicit invocation) to the fact that the receiving code can be (and ideally is) completely oblivious to the quantification that applies to it.For a first AspectJ program, let's take a look at Hello World:
public class Hello {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
That's it. This is a complete AspectJ program (as well as a complete Java program). All Java programs are AspectJ programs. But this isn't very interesting, so let's add an aspect:
public aspect A {
// declare a pointcut
pointcut mainExecutes() :
execution(public static void main(String[]));
// define some advice on the pointcut
before() : mainExecutes() {
org.somewhere.subsystem.init();
}
}
The purpose of this aspect is to initialize some subsystem before the main() method executes. First, we declare an AspectJ pointcut, and name it mainExecutes(). This declaration binds the name mainExecutes to executions of the provided method name.
Some Definitions:
But why separate this at all? Wouldn't copying all the subsystem initialization stuff into main() be easier? Perhaps in some cases, yes. But if the subsystem initialization is a completely separate concern than that of the main program, or if you have multiple subsystem initializations to perform, it may be worth considering the modularity afforded by a solution like the above. Next week we'll examine more interesting examples.
Aspects may contain many pointcuts and advice definitions, and multiple aspects can affect the same join point.
This gives you enough to complete Homework 1, the main purpose of which is to ensure that you can get AspectJ working.
Please contact me at mdeters@cse.wustl.edu if you have any questions regarding these notes.
Help on setting up AspectJ
Back to AspectJ Seminar course calendar