You are on page 1of 39

Presenters

Aspect-Oriented Programming
with ➢ Daniel Lohmann
C++ and AspectC++ dl@aspectc.org

– University of Erlangen-Nuremberg, Germany

AOSD 2005 Tutorial ➢ Olaf Spinczyk


os@aspectc.org

– University of Erlangen-Nuremberg, Germany

Introduction
University of Erlangen-Nuremberg
Computer Science 4 © 2005 Daniel Lohmann and Olaf Spinczyk I/1 Introduction © 2005 Daniel Lohmann and Olaf Spinczyk I/2

Schedule This Tutorial is about ...


➢ Writing aspect-oriented code with pure C++

Part Title Time – basic implementation techniques using C++ idioms

I Introduction 10m – limitations of the pure C++ approach


II AOP with pure C++ 40m ➢ Programming with AspectC++
III AOP with AspectC++ 70m – language concepts, implementation, tool support
IV Tool support for AspectC++ 30m
– this is an AspectC++ tutorial
V Real-World Examples 20m
VI Summary and Discussion 10m ➢ Programming languages and concepts
– no coverage of other AOSD topics like analysis or design

Introduction © 2005 Daniel Lohmann and Olaf Spinczyk I/3 Introduction © 2005 Daniel Lohmann and Olaf Spinczyk I/4
Aspect-Oriented Programming Why AOP with C++?
➢ AOP is about modularizing crosscutting concerns ➢ Widely accepted benefits from using AOP
well modularized concern aspect
 avoidance of code redundancy, better reusability,
maintainability, configurability, the code better reflects the
design, ...
➢ Enormous existing C++ code base
 maintainance: extensions are often crosscutting

badly modularized
➢ Millions of programmers use C++
without AOP with AOP  for many domains C++ is the adequate language
 they want to benefit from AOP (as Java programmers do)
➢ Examples: tracing, synchronization, security, ➢ How can the AOP community help?
buffering, error handling, constraint checks, ...  Part II: describe how to apply AOP with built-in
mechanisms
 Part III-V: provide special language mechanisms for AOP
Introduction © 2005 Daniel Lohmann and Olaf Spinczyk I/5 Introduction © 2005 Daniel Lohmann and Olaf Spinczyk I/6

Scenario: A Queue utility class The Simple Queue Class


namespace util { Item* dequeue() {
class Item { printf(" > Queue::dequeue()\n");
friend class Queue; Item* res = first;
Item* next; if( first == last )
public: first = last = 0;
Item() : next(0){} else
}; first = first->next;
printf(" < Queue::dequeue()\n");
class Queue { return res;
Item* first; }
Item* last; }; // class Queue
public: } // namespace util
Queue() : first(0), last(0) {}

void enqueue( Item* item ) {


printf( " > Queue::enqueue()\n" );
if( last ) {
last->next = item;
last = item;
} else
last = first = item;
printf( " < Queue::enqueue()\n" );
}
Introduction © 2005 Daniel Lohmann and Olaf Spinczyk I/7 Introduction © 2005 Daniel Lohmann and Olaf Spinczyk I/8
Scenario: The Problem The Not So Simple Queue Class
Various users of Queue demand extensions: class Queue { Item* dequeue() {
Item *first, *last; Item* res;
Please extend the int counter; lock.enter();
os::Mutex lock; try {
Queue class by an
public: res = first;
element counter! Queue () : first(0), last(0) { if (first == last)
counter = 0; first = last = 0;
I want Queue to } else first = first->next;
throw exceptions! void enqueue(Item* item) { if (counter > 0) –counter;
lock.enter(); if (res == 0)
try { throw QueueEmptyError();
Queue should be if (item == 0) } catch (...) {
thread-safe! throw QueueInvalidItemError(); lock.leave();
if (last) { throw;
last->next = item; }
last = item; lock.leave();
} else { last = first = item; } return res;
++counter; }
} catch (...) { int count() { return counter; }
lock.leave(); throw; }; // class Queue
}
lock.leave();
}
Introduction © 2005 Daniel Lohmann and Olaf Spinczyk I/9 Introduction © 2005 Daniel Lohmann and Olaf Spinczyk I/10

What Code Does What? Problem Summary


class Queue {
Item *first, *last;
Item* dequeue() {
Item* res;
The component code is “polluted” with code for several
int counter;
os::Mutex lock;
lock.enter(); logically independent concerns, thus it is ...
try {
public: res = first; ➢ hard to write the code
Queue () : first(0), last(0) { if (first == last)
counter = 0; first = last = 0; – many different things have to be considered simultaneously
} else first = first->next;
void enqueue(Item* item) {
lock.enter();
if (counter > 0) –counter;
if (res == 0)
➢ hard to read the code
try {
if (item == 0)
throw QueueEmptyError(); – many things are going on at the same time
} catch (...) {
throw QueueInvalidItemError();
if (last) {
lock.leave();
throw;
➢ hard to maintain and evolve the code
last->next = item;
last = item;
} – the implementation of concerns such as locking is scattered
lock.leave();
} else { last = first = item; } return res; over the entire source base (a “crosscutting concern”)
++counter; }
} catch (...) { int count() { return counter; } ➢ hard to configure at compile time
lock.leave(); throw; }; // class Queue
} – the users get a “one fits all” queue class
lock.leave();
}
Introduction © 2005 Daniel Lohmann and Olaf Spinczyk I/11 Introduction © 2005 Daniel Lohmann and Olaf Spinczyk I/12
Aspect-Oriented Programming Outline
with
C++ and AspectC++ ➢ We go through the Queue example and...
– decompose the "one-fits-all" code into modular units
AOSD 2005 Tutorial
– apply simple AOP concepts

– use only C/C++ language idioms and elements

➢ After we went through the example, we...


will try to understand the benefits
Part II – AOP with C++ –
and limitations of a pure C++ approach

– motivate the need for an advanced language


with built-in AOP concepts: AspectC++

AOP with C++ © 2005 Daniel Lohmann and Olaf Spinczyk II/1 AOP with C++ © 2005 Daniel Lohmann and Olaf Spinczyk II/2

Configuring with the Preprocessor? Preprocessor


While we are able to enable/disable features
class Queue { Item* dequeue() {
Item *first, *last; Item* res; ➢
#ifdef COUNTING_ASPECT #ifdef LOCKING_ASPECT
int counter;
#endif
lock.enter();
try {
 the code is not expressed in a modular fashion
#ifdef LOCKING_ASPECT #endif
os::Mutex lock;
#endif
res = first;
if (first == last)
 aspectual code is spread out over the entire code base
public:
Queue () : first(0), last(0) {
first = last = 0;
else first = first->next;
 the code is almost unreadable
#ifdef COUNTING_ASPECT #ifdef COUNTING_ASPECT
counter = 0; if (counter > 0) --counter;
#endif #endif

Preprocessor is the "typical C way" to solve


} #ifdef ERRORHANDLING_ASPECT
void enqueue(Item* item) { if (res == 0) ➢
#ifdef LOCKING_ASPECT throw QueueEmptyError();
lock.enter();
try {
#endif
#endif
#ifdef LOCKING_ASPECT
} catch (...) {
problems
#ifdef ERRORHANDLING_ASPECT lock.leave();
if (item == 0) throw;
throw QueueInvalidItemError(); }
#endif
if (last) {
last->next = item;
lock.leave();
#endif
return res;
➢ Which C++ mechanism could be used instead?
last = item; }
} else { last = first = item; } #ifdef COUNTING_ASPECT

Templates!
#ifdef COUNTING_ASPECT int count() { return counter; }
++counter; #endif
#endif }; // class Queue
#ifdef LOCKING_ASPECT
} catch (...) {
lock.leave(); throw;
}
lock.leave();
#endif
AOP with C++
}
© 2005 Daniel Lohmann and Olaf Spinczyk II/3 AOP with C++ © 2005 Daniel Lohmann and Olaf Spinczyk II/4
Templates Using Templates
➢ Templates can be used to construct generic code Templates are typically used to implement
 To actually use the code, it has to be instantiated generic abstract data types:
➢ Just as preprocessor directives
 templates are evaluated at compile-time // Generic Array class
// Elements are stored in a resizable buffer
 do not cause any direct runtime overhead (if applied properly)
template< class T >
class Array {
T* buf; // allocated memory
#define add1(T, a, b) \ public:
(((T)a)+((T)b)) T operator[]( int i ) const {
return buf[ i ];
template <class T> }
T add2(T a, T b) { return a + b; }
...
printf(“%d”, add1(int, 1, 2)); };
printf(“%d”, add2<int>(1, 2));

AOP with C++ © 2005 Daniel Lohmann and Olaf Spinczyk II/5 AOP with C++ © 2005 Daniel Lohmann and Olaf Spinczyk II/6

AOP with Templates Aspects as Wrapper Templates


➢ Templates allow us to encapsulate aspect code The counting aspect is expressed as a wrapper
independently from the component code template class, that derives from the component class:
➢ Aspect code is "woven into" the component // generic wrapper (aspect), that adds counting to any queue class
// Q, as long it has the proper interface
code by instantiating these templates template <class Q> // Q is the component class this
class Counting_Aspect : public Q { // aspect should be applied on
// component code int counter;
class Queue { public:
... void enqueue(Item* item) { // execute advice code after join point
void enqueue(Item* item) { Q::enqueue(item); counter++;
if (last) { last->next = item; last = item; } }
else { last = first = item; } Item* dequeue() { // again, after advice
} Item* res = Q::dequeue(item);
Item* dequeue() { if (counter > 0) counter--;
Item* res = first; return res;
if (first == last) first = last = 0; }
else first = first->next; // this method is added to the component code (introduction)
return res; int count() const { return counter; }
} };
};
AOP with C++ © 2005 Daniel Lohmann and Olaf Spinczyk II/7 AOP with C++ © 2005 Daniel Lohmann and Olaf Spinczyk II/8
Weaving Our First Aspect – Lessons Learned

We can define a type alias (typedef) that combines ➢ Aspects can be implemented by template wrappers
both, component and aspect code (weaving):  Aspect inherits from component class, overrides relevant methods
 Introduction of new members (e.g. counter variable) is easy
 Weaving takes place by defining (and using) type aliases
// component code
class Queue { ... }
// The aspect (wrapper class)
➢ The aspect code is generic
template <class Q>  It can be applied to "any" component that
class Counting_Aspect : public Q { ... } exposes the same interface (enqueue, dequeue)
// template instantiation
typedef Counting_Aspect<Queue> CountingQueue;  Each application of the aspect has to be specified explicitly
int main() { ➢ The aspect code is clearly separated
CountingQueue q;
q.enqueue(new Item);
 All code related to counting is gathered in one template class
q.enqueue(new Item);  Counting aspect and queue class can be evolved independently
printf(“number of items in q: %u\n”, q.count());
return 0;
(as long as the interface does not change)
}

AOP with C++ © 2005 Daniel Lohmann and Olaf Spinczyk II/9 AOP with C++ © 2005 Daniel Lohmann and Olaf Spinczyk II/10

Error Handling Aspect Combining Aspects


Adding an error handling aspect (exceptions) is We already know how to weave with a single aspect.
straight-forward. We just need a wrapper template: Weaving with multiple aspects is also straightforward:
// another aspect (as wrapper template)
template <class Q> // component code
class Exceptions_Aspect : public Q { class Queue { ... }
void enqueue(Item* item) { // this advice is executed before the // wrappers (aspects)
if (item == 0) // component code (before advice) template <class Q>
throw QueueInvalidItemError(); class Counting_Aspect : public Q { ... }
Q::enqueue(item); template <class Q>
} class Exceptions_Aspect : public Q { ... }
// template instantiation (weaving)
Item* dequeue() { // after advice typedef Exceptions_Aspect< Counting_Aspect< Queue > > ExceptionsCountingQueue;
Item* res = Q::dequeue();
if (res == 0) throw QueueEmptyError();
return res;
}
}

AOP with C++ © 2005 Daniel Lohmann and Olaf Spinczyk II/11 AOP with C++ © 2005 Daniel Lohmann and Olaf Spinczyk II/12
Ordering Locking Aspect
➢ In what order should we apply our aspects? With what we learned so far, putting together the
Aspect code is executed outermost-first: locking aspect should be simple:
typedef Exceptions_Aspect< // first Exceptions, then Counting
Counting_Aspect< Queue > > ExceptionsCountingQueue;
template <class Q> Item* dequeue() {
typedef Counting_Aspect< // first Counting, then Exceptions class Locking_Aspect : public Q { Item* res;
Exceptions_Aspect< Queue > > ExceptionsCountingQueue; public: lock.enter();
Mutex lock; try {
➢ Aspects should be independent of ordering void enqueue(Item* item) { res = Q::dequeue(item);
lock.enter(); } catch (...) {
 For dequeue(), both Exceptions_Aspect and Counting_Aspect give
try { lock.leave();
after advice. Shall we count first or check first? Q::enqueue(item); throw;
 Fortunately, our implementation can deal with both cases: } catch (...) { }
lock.leave(); lock.leave();
Item* res = Q::dequeue(item); throw; return res;
// its ok if we run before Exceptions_Wrapper } }
lock.leave(); };
if (counter > 0) counter--;
}
return res;

AOP with C++ © 2005 Daniel Lohmann and Olaf Spinczyk II/13 AOP with C++ © 2005 Daniel Lohmann and Olaf Spinczyk II/14

Locking Advice (2) Advice Code Duplication


Locking_Aspect uses an around advice, that proceeds with Specifying the same advice for several joinpoints
the component code in the middle of the aspect code: leads to code duplication:

template <class Q> Item* dequeue() { template <class Q> Item* dequeue() {
class Locking_Aspect : public Q { Item* res; class Locking_Aspect : public Q { Item* res;
public: lock.enter(); public: lock.enter();
Mutex lock; try { Mutex lock; try {
void enqueue(Item* item) { res = Q::dequeue(item); void enqueue(Item* item) { res = Q::dequeue(item);
lock.enter(); } catch (...) { lock.enter(); } catch (...) {
try { lock.leave(); try { lock.leave();
Q::enqueue(item); throw; Q::enqueue(item); throw;
} catch (...) { } } catch (...) { }
lock.leave(); lock.leave(); lock.leave(); lock.leave();
throw; return res; throw; return res;
} } } }
lock.leave(); }; lock.leave(); };
} }

AOP with C++ © 2005 Daniel Lohmann and Olaf Spinczyk II/15 AOP with C++ © 2005 Daniel Lohmann and Olaf Spinczyk II/16
Dealing with Joinpoint Sets Reusable Advice Code
To specify advice for a set of joinpoints, The advice code is expressed as template function,
the joinpoints must have a uniform interface: which is later instantiated with an action class:
template <class Q> template <class Q>
class Locking_Aspect2 : public Q { class Locking_Aspect : public Q {
public: ...
Mutex lock; template <class action> // template inside another template
void advice(action* a) {
// wrap joinpoint invocations into action classes lock.enter();
struct EnqueueAction { try {
Item* item; a->proceed(this);
void proceed(Q* q) { q->enqueue(item); } } catch (...) {
}; lock.leave();
throw;
struct DequeueAction { }
Item* res; lock.leave();
void proceed(Q* q) { res = q->dequeue(); } }
}; ...
... };

AOP with C++ © 2005 Daniel Lohmann and Olaf Spinczyk II/17 AOP with C++ © 2005 Daniel Lohmann and Olaf Spinczyk II/18

Binding Advice to Joinpoints Reusing Advice – Lessons Learned


Using the action classes we have created, the advice ➢ We avoided advice code duplication, by...
code is now nicely encapsulated in a single function:  delegating the invocation of the original
code (proceed) to action classes
 making the aspect code itself a template function
template <class Q>
class Locking_Aspect2 : public Q {
 instantiating the aspect code with the action classes
...
void enqueue(Item* item) {
EnqueueAction tjp = {item};
advice(&tjp); ➢ Compilers will probably generate less efficient code
}
Item* dequeue() {
 Additional overhead for storing argument/result values
DequeueAction tjp;
advice(&tjp);
return tjp.res;
}
...
};

AOP with C++ © 2005 Daniel Lohmann and Olaf Spinczyk II/19 AOP with C++ © 2005 Daniel Lohmann and Olaf Spinczyk II/20
Putting Everyting Together “Obliviousness”
We can now instantiate the combined ... is an essential property of AOP: the component code
Queue class, which uses all aspects: should not have to be aware of aspects, but ...
(For just 3 aspects, the typedef
is already getting rather complex)
➢ the extended Queue cannot be named “Queue”
– our aspects are selected through a naming scheme
typedef Locking_Aspect2<Exceptions_Aspect<Counting_Aspect
<Queue> > > CountingQueueWithExceptionsAndLocking; (e.g. CountingQueueWithExceptionsAndLocking).
// maybe a little bit more readable ... ➢ using wrapper class names violates the idea of
typedef Counting_Aspect<Queue> CountingQueue; obliviousness
typedef Exceptions_Aspect<CountingQueue> CountingQueueWithExceptions;
typedef Locking_Aspect<CountingQueueWithExceptions>
CountingQueueWithExceptionsAndLocking; Preferably, we want to hide the aspects from client
code that uses affected components.

AOP with C++ © 2005 Daniel Lohmann and Olaf Spinczyk II/21 AOP with C++ © 2005 Daniel Lohmann and Olaf Spinczyk II/22

Hiding Aspects Hiding Aspects (2)


➢ Aspects can be hidden using C++ namespaces namespace components {
class Queue { ... };
}
namespace aspects {
➢ Three separate namespaces are introduced template <class Q>
class Counting_Aspect : public Q { ... };
}
– namespace components: component code for class Queue namespace configuration {
// select counting queue
typedef aspects::Counting_Aspect<components::Queue> Queue;
– namespace aspects: aspect code for class Queue }

– namespace configuration: selection of desired aspects for // client code can import configuration namespace and use
// counting queue as “Queue”
class Queue using namespace configuration;

void client_code () {
➢ The complex naming schemes as seen on the Queue queue; // Queue with all configured aspects
previous slide is avoided }
queue.enqueue (new MyItem);

AOP with C++ © 2005 Daniel Lohmann and Olaf Spinczyk II/23 AOP with C++ © 2005 Daniel Lohmann and Olaf Spinczyk II/24
Obliviousness – Lessons Learned Limitations
➢ Aspect configuration, aspect code, and client code For simple aspects the presented techniques work
can be separated using C++ namespaces quite well, but a closer look reveals limitations:
➢ Joinpoint types
– name conflicts are avoided  no destinction between function call and execution
 no generic interface to joinpoint context
➢ Except for using the configuration namespace the  no advice for private member functions
client code does not have to be changed ➢ Quantification
 no flexible way to describe the target components
– obliviousness is (mostly) achieved on the client-side (like AspectJ/AspectC++ pointcuts)
 applying the same aspect to classes with different interfaces is
What about obliviousness in the extended classes? impossible or ends with excessive template metaprogramming

AOP with C++ © 2005 Daniel Lohmann and Olaf Spinczyk II/25 AOP with C++ © 2005 Daniel Lohmann and Olaf Spinczyk II/26

Limitations (continued) Conclusions


➢ Scalibility ➢ C++ templates can be used for separation of
 the wrapper code can easily outweigh the aspect code concerns in C++ code without special tool support
 explicitly defining the aspect order for every affected class ➢ However, the lack of expressiveness and scalibility
is error-prone and cumbersome restricts these techniques to projects with ...
 excessive use of templates and namespaces makes the  only a small number of aspects
code hard to understand and debug
 few or no aspect interactions
 aspects with a non-generic nature
 component code that is “aspect-aware”
“AOP with pure C++ is like OO with pure C” ➢ However, switching to tool support is easy!
 aspects have already been extracted and modularized.
 transforming template-based aspects to code expected by
dedicated AOP tools is only mechanical labor

AOP with C++ © 2005 Daniel Lohmann and Olaf Spinczyk II/27 AOP with C++ © 2005 Daniel Lohmann and Olaf Spinczyk II/28
References/Other Approaches
K. Czarnecki, U.W. Eisenecker et. al.: "Aspektorientierte Programmierung in
C++", iX – Magazin für professionelle Informationstechnik, 08/09/10, 2001
 A comprehensive analysis of doing AOP with pure C++: what's possible and what not
 http://www.heise.de/ix/artikel/2001/08/143/

A. Alexandrescu: "Modern C++ Design – Generic Programming and Design


Patterns Applied", Addison-Wesley, C++ in depth series, 2001
 Introduces "policy-based design", a technique for advanced separation of concerns in C++
 Policy-based design tries to achieve somewhat similar goals as AOP does
 http://www.moderncppdesign.com/

Other suggestions towards AOP with pure C++:


 C. Diggins: "Aspect Oriented Programming in C++"
http://www.heron-language.com/aspect-cpp.html
 D. Vollmann: "Visibility of Join-Points in AOP and Implementation Languages"
http://i44w3.info.uni-karlsruhe.de/~pulvermu/workshops/aosd2002/submissions/vollmann.pdf

AOP with C++ © 2005 Daniel Lohmann and Olaf Spinczyk II/29
Aspect-Oriented Programming The Simple Queue Class Revisited
with
C++ and AspectC++ namespace util {
class Item {
Item* dequeue() {
printf(" > Queue::dequeue()\n");
friend class Queue; Item* res = first;
Item* next; if( first == last )
AOSD 2005 Tutorial public: first = last = 0;
Item() : next(0){} else
}; first = first->next;
printf(" < Queue::dequeue()\n");
class Queue { return res;
Item* first; }
Item* last; }; // class Queue
public:
Queue() : first(0), last(0) {} } // namespace util

Part III – Aspect C++ void enqueue( Item* item ) {


printf( " > Queue::enqueue()\n" );
if( last ) {
last->next = item;
last = item;
} else
last = first = item;
printf( " < Queue::enqueue()\n" );
}
Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/1 Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/2

Queue: Demanded Extensions Element counting: The Idea

I. Element counting Please extend the


Queue class by an
element counter!
➢ Increment a counter variable after each
execution of util::Queue::enqueue()
II. Errorhandling
(signaling of errors by exceptions)
➢ Decrement it after each
execution of util::Queue::dequeue()

III. Thread safety


(synchronization by mutex variables)

Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/3 Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/4
ElementCounter1 ElementCounter1 - Elements

aspect ElementCounter { aspect ElementCounter {


We introduced a new aspect named
int counter; int counter; ElementCounter.
ElementCounter() { ElementCounter() {
counter = 0; counter = 0; An aspect starts with the keyword aspect
} } and is syntactically much like a class.
advice execution("% util::Queue::enqueue(...)") : after() { advice execution("% util::Queue::enqueue(...)") : after() {
++counter; ++counter;
printf( " Aspect ElementCounter: # of elements = %d\n", counter ); printf( " Aspect ElementCounter: # of elements = %d\n", counter );
} }
advice execution("% util::Queue::dequeue(...)") : after() { advice execution("% util::Queue::dequeue(...)") : after() {
if( counter > 0 ) --counter; if( counter > 0 ) --counter;
printf( " Aspect ElementCounter: # of elements = %d\n", counter ); printf( " Aspect ElementCounter: # of elements = %d\n", counter );
} }
}; };
ElementCounter1.ah ElementCounter1.ah

Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/5 Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/6

ElementCounter1 - Elements ElementCounter1 - Elements

aspect ElementCounter { aspect ElementCounter {


Like a class, an aspect We give after advice (= some
int counter; can define data members, int counter; crosscuting code to be executed
ElementCounter() {
constructors and so on ElementCounter() { after certain control flow positions)
counter = 0; counter = 0;
} }

advice execution("% util::Queue::enqueue(...)") : after() { advice execution("% util::Queue::enqueue(...)") : after() {


++counter; ++counter;
printf( " Aspect ElementCounter: # of elements = %d\n", counter ); printf( " Aspect ElementCounter: # of elements = %d\n", counter );
} }
advice execution("% util::Queue::dequeue(...)") : after() { advice execution("% util::Queue::dequeue(...)") : after() {
if( counter > 0 ) --counter; if( counter > 0 ) --counter;
printf( " Aspect ElementCounter: # of elements = %d\n", counter ); printf( " Aspect ElementCounter: # of elements = %d\n", counter );
} }
}; };
ElementCounter1.ah ElementCounter1.ah

Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/7 Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/8
ElementCounter1 - Elements ElementCounter1 - Elements
This pointcut expression denotes
aspect ElementCounter {
where the advice should be given. aspect ElementCounter {
(After execution of methods that match
int counter; the pattern) int counter; Aspect member elements can be
ElementCounter() { ElementCounter() { accessed from within the advice body
counter = 0; counter = 0;
} }

advice execution("% util::Queue::enqueue(...)") : after() { advice execution("% util::Queue::enqueue(...)") : after() {


++counter; ++counter;
printf( " Aspect ElementCounter: # of elements = %d\n", counter ); printf( " Aspect ElementCounter: # of elements = %d\n", counter );
} }
advice execution("% util::Queue::dequeue(...)") : after() { advice execution("% util::Queue::dequeue(...)") : after() {
if( counter > 0 ) --counter; if( counter > 0 ) --counter;
printf( " Aspect ElementCounter: # of elements = %d\n", counter ); printf( " Aspect ElementCounter: # of elements = %d\n", counter );
} }
}; };
ElementCounter1.ah ElementCounter1.ah

Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/9 Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/10

ElementCounter1 - Result ElementCounter1 – What's next?


int main() {
util::Queue queue;
➢ The aspect is not the ideal place to store the counter,
printf("main(): enqueueing an item\n");
queue.enqueue( new util::Item );
because it is shared between all Queue instances
printf("main(): dequeueing two items\n"); ➢ Ideally, counter becomes a member of Queue
Util::Item* item;
item = queue.dequeue(); main(): enqueueing am item
item = queue.dequeue(); > Queue::enqueue(00320FD0) ➢ In the next step, we
} < Queue::enqueue(00320FD0)
Aspect ElementCounter: # of elements = 1 – move counter into Queue by introduction
main(): dequeueing two items
main.cc > Queue::dequeue() – expose context about the aspect invocation to
< Queue::dequeue() returning 00320FD0 access the current Queue instance
Aspect ElementCounter: # of elements = 0
> Queue::dequeue()
< Queue::dequeue() returning 00000000
Aspect ElementCounter: # of elements = 0
<Output>
Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/11 Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/12
ElementCounter2 ElementCounter2 - Elements
aspect ElementCounter { aspect ElementCounter {
private: private:
advice "util::Queue" : int counter; advice "util::Queue" : int counter; Introduces a new data member
public: public: counter into all classes denoted
advice "util::Queue" : int count { return counter; } const advice "util::Queue" : int count {
by the pointcut "util::Queue"
return counter; } const

advice execution("% util::Queue::enqueue(...)") advice execution("% util::Queue::enqueue(...)")


&& that(queue) : after( util::Queue& queue ) { && that(queue) : after( util::Queue& queue ) {
++queue.counter; ++queue.counter;
printf( " Aspect ElementCounter: # of elements = %d\n", queue.count() ); printf( " Aspect ElementCounter: # of elements = %d\n", queue.count() );
} }
advice execution("% util::Queue::dequeue(...)") advice execution("% util::Queue::dequeue(...)")
&& that(queue) : after( util::Queue& queue ) { && that(queue) : after( util::Queue& queue ) {
if( queue.count() > 0 ) --queue.counter; if( queue.count() > 0 ) --queue.counter;
printf( " Aspect ElementCounter: # of elements = %d\n", queue.count() ); printf( " Aspect ElementCounter: # of elements = %d\n", queue.count() );
} }
advice construction("util::Queue") advice construction("util::Queue")
&& that(queue) : before( util::Queue& queue ) { && that(queue) : before( util::Queue& queue ) {
queue.counter = 0; queue.counter = 0;
} }
}; };

ElementCounter2.ah ElementCounter2.ah
Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/13 Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/14

ElementCounter2 - Elements ElementCounter2 - Elements


aspect ElementCounter { aspect ElementCounter {
A context variable queue is bound
private:
We also introduce a public private: to that (the calling instance).
advice "util::Queue" : int counter; method to read the counter advice "util::Queue" : int counter; The calling instance has to be
public: public:
an util::Queue
advice "util::Queue" : int count { return counter; } const advice "util::Queue" : int count { return counter; } const

advice execution("% util::Queue::enqueue(...)") advice execution("% util::Queue::enqueue(...)")


&& that(queue) : after( util::Queue& queue ) { && that(queue) : after( util::Queue& queue ) {
++queue.counter; ++queue.counter;
printf( " Aspect ElementCounter: # of elements = %d\n", queue.count() ); printf( " Aspect ElementCounter: # of elements = %d\n", queue.count() );
} }
advice execution("% util::Queue::dequeue(...)") advice execution("% util::Queue::dequeue(...)")
&& that(queue) : after( util::Queue& queue ) { && that(queue) : after( util::Queue& queue ) {
if( queue.count() > 0 ) --queue.counter; if( queue.count() > 0 ) --queue.counter;
printf( " Aspect ElementCounter: # of elements = %d\n", queue.count() ); printf( " Aspect ElementCounter: # of elements = %d\n", queue.count() );
} }
advice construction("util::Queue") advice construction("util::Queue")
&& that(queue) : before( util::Queue& queue ) { && that(queue) : before( util::Queue& queue ) {
queue.counter = 0; queue.counter = 0;
} }
}; };

ElementCounter2.ah ElementCounter2.ah
Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/15 Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/16
ElementCounter2 - Elements ElementCounter2 - Elements
aspect ElementCounter { aspect ElementCounter {
private: The context variable queue is private: By giving construction advice
advice "util::Queue" : int counter; used to access the calling advice "util::Queue" : int counter; we ensure that counter gets
public: public:
instance. initialized
advice "util::Queue" : int count { return counter; } const advice "util::Queue" : int count { return counter; } const

advice execution("% util::Queue::enqueue(...)") advice execution("% util::Queue::enqueue(...)")


&& that(queue) : after( util::Queue& queue ) { && that(queue) : after( util::Queue& queue ) {
++queue.counter; ++queue.counter;
printf( " Aspect ElementCounter: # of elements = %d\n", queue.count() ); printf( " Aspect ElementCounter: # of elements = %d\n", queue.count() );
} }
advice execution("% util::Queue::dequeue(...)") advice execution("% util::Queue::dequeue(...)")
&& that(queue) : after( util::Queue& queue ) { && that(queue) : after( util::Queue& queue ) {
if( queue.count() > 0 ) --queue.counter; if( queue.count() > 0 ) --queue.counter;
printf( " Aspect ElementCounter: # of elements = %d\n", queue.count() ); printf( " Aspect ElementCounter: # of elements = %d\n", queue.count() );
} }
advice construction("util::Queue") advice construction("util::Queue")
&& that(queue) : before( util::Queue& queue ) { && that(queue) : before( util::Queue& queue ) {
queue.counter = 0; queue.counter = 0;
} }
}; };

ElementCounter2.ah ElementCounter2.ah
Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/17 Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/18

ElementCounter2 - Result ElementCounter2 - Result


int main() { int main() {
util::Queue queue; util::Queue queue;
printf("main(): Queue contains %d items\n", queue.count()); printf("main(): Queue contains %d items\n", queue.count());
printf("main(): enqueueing some items\n"); printf("main(): enqueueing some items\n");
queue.enqueue(new util::Item); queue.enqueue(new util::Item);
queue.enqueue(new util::Item); queue.enqueue(new util::Item);
printf("main(): Queue contains %d items\n", queue.count()); printf("main(): Queue contains main(): Queue queue.count());
%d items\n", contains 0 items
printf("main(): dequeueing one items\n"); printf("main(): dequeueing one main(): enqueueing some items
items\n");
util::Item* item; util::Item* item; > Queue::enqueue(00320FD0)
item = queue.dequeue(); item = queue.dequeue(); < Queue::enqueue(00320FD0)
printf("main(): Queue contains %d items\n", queue.count()); printf("main(): Queue contains %dAspect ElementCounter:
items\n", # of elements = 1
queue.count());
} } > Queue::enqueue(00321000)
< Queue]::enqueue(00321000)
Aspect ElementCounter: # of elements = 2
main.cc main.cc main(): Queue contains 2 items
main(): dequeueing one items
> Queue::dequeue()
< Queue::dequeue() returning 00320FD0
Aspect ElementCounter: # of elements = 1
main(): Queue contains 1 items
<Output>
Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/19 Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/20
ElementCounter – Lessons Learned Syntactic Elements
aspect name pointcut expression advice type
You have seen...
➢ the most important concepts of AspectC++

– Aspects are introduced with the keyword aspect aspect ElementCounter {

– They are much like a class, may contain methods, advice execution("% util::Queue::enqueue(...)") : after()
data members, types, inner classes, etc. {
printf( " Aspect ElementCounter: after Queue::enqueue!\n" );
– Additionaly, aspects can give advice to be woven in }
at certain positions (joinpoints). Advice can be given to
 Functions/Methods/Constructors: code to execute (code advice) ...
};
 Classes or structs: new elements (introductions)
– Joinpoints are described by pointcut expressions
ElementCounter1.ah
advice body
➢ We will now take a closer look at some of them

Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/21 Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/22

Joinpoints Pointcut Expressions


➢ A joinpoint denotes a position to give advice ➢ Pointcut expressions are made from ...
– Code joinpoint – match expressions, e.g. "% util::queue::enqueue(...)"
a point in the control flow of a running program, e.g. 
are matched against C++ programm entities → name joinpoints
 execution of a function  support wildcards
 call of a function – pointcut functions, e.g execution(...), call(...), that(...)
 execution: all points in the control flow, where a function is about to
– Name joinpoint
be executed → code joinpoints
 a named C++ program entity (identifier)
 call: all points in the control flow, where a function is about to be
 class, function, method, type, namespace
called → code joinpoints

➢ Joinpoints are given by pointcut expressions


➢ Pointcut functions can be combined into expressions
 using logical connectors: &&, ||, !
 a pointcut expression describes a set of joinpoints  Example: call("% util::Queue::enqueue(...)") && within("% main(...)")

Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/23 Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/24
Advice Before / After Advice
Advice to functions
– before advice with execution joinpoints:
class ClassA {
 Advice code is executed before the original code public:
 Advice may read/modify parameter values advice execution(“void ClassA::foo()”) : before() void foo(){
printf(“ClassA::foo()”\n);
– after advice advice execution(“void ClassA::foo()”) : after() }
 Advice code is executed after the original code }
 Advice may read/modify return value
– around advice
 Advice code is executed instead of the original code with call joinpoints:
 Original code may be called explicitly: tjp->proceed() int main(){
printf(“main()\n”);
Introductions advice call (“void ClassA::foo()”) : before() ClassA a;
a.foo();
 Additional methods, data members, etc. are added to the class advice call (“void ClassA::foo()”) : after() }
 Can be used to extend the interface of a class

Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/25 Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/26

Around Advice Introductions


with execution joinpoints:
class ClassA { class ClassA {
advice execution(“void ClassA::foo()”) : around() public: private:
before code void foo(){ advice “ClassA” : element to introduce public:
printf(“ClassA::foo()”\n);
tjp->proceed() } void foo(){
} printf(“ClassA::foo()”\n);
public:
after code }
advice “ClassA” : element to introduce
}

with call joinpoints:


int main(){
advice call(“void ClassA::foo()”) : around()
printf(“main()\n”);
before code
ClassA a;
a.foo();
tjp->proceed()
}
after code

Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/27 Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/28
Queue: Demanded Extensions Errorhandling: The Idea
➢ We want to check the following constraints:
I. Element counting – enqueue() is never called with a NULL item
– dequeue() is never called on an empty queue
I want Queue to
throw exceptions! ➢ In case of an error an exception should be thrown
II. Errorhandling
(signaling of errors by exceptions) ➢ To implement this, we need access to ...
– the parameter passed to enqueue()
– the return value returned by dequeue()
III. Thread safety ... from within the advice
(synchronization by mutex variables)

Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/29 Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/30

ErrorException ErrorException - Elements


namespace util { namespace util {
struct QueueInvalidItemError {}; struct QueueInvalidItemError {};
struct QueueEmptyError {}; struct QueueEmptyError {}; We give advice to be executed before
} }
enqueue() and after dequeue()
aspect ErrorException { aspect ErrorException {

advice execution("% util::Queue::enqueue(...)") && args(item) advice execution("% util::Queue::enqueue(...)") && args(item)
: before(util::Item* item) { : before(util::Item* item) {
if( item == 0 ) if( item == 0 )
throw util::QueueInvalidItemError(); throw util::QueueInvalidItemError();
} }
advice execution("% util::Queue::dequeue(...)") && result(item) advice execution("% util::Queue::dequeue(...)") && result(item)
: after(util::Item* item) { : after(util::Item* item) {
if( item == 0 ) if( item == 0 )
throw util::QueueEmptyError(); throw util::QueueEmptyError();
} }
}; };
ErrorException.ah ErrorException.ah

Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/31 Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/32
ErrorException - Elements ErrorException - Elements
namespace util { namespace util {
struct QueueInvalidItemError {};
A context variable item is bound to struct QueueInvalidItemError
Here{};
the context variable item is
struct QueueEmptyError {}; struct QueueEmptyError {};
}
the first argument of type util::Item* }
bound to the result of type util::Item*
passed to the matching methods returned by the matching methods
aspect ErrorException { aspect ErrorException {

advice execution("% util::Queue::enqueue(...)") && args(item) advice execution("% util::Queue::enqueue(...)") && args(item)
: before(util::Item* item) { : before(util::Item* item) {
if( item == 0 ) if( item == 0 )
throw util::QueueInvalidItemError(); throw util::QueueInvalidItemError();
} }
advice execution("% util::Queue::dequeue(...)") && result(item) advice execution("% util::Queue::dequeue(...)") && result(item)
: after(util::Item* item) { : after(util::Item* item) {
if( item == 0 ) if( item == 0 )
throw util::QueueEmptyError(); throw util::QueueEmptyError();
} }
}; };
ErrorException.ah ErrorException.ah

Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/33 Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/34

ErrorException – Lessons Learned Queue: Demanded Extensions


You have seen how to ...
I. Element counting
➢ use different types of advice Queue should be
thread-safe!
– before advice
– after advice
II. Errorhandling
(signaling of errors by exceptions)
➢ expose context in the advice body
– by using args to read/modify parameter values
– by using result to read/modify the return value
III. Thread safety
(synchronization by mutex variables)

Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/35 Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/36
Thread Safety: The Idea LockingMutex
aspect LockingMutex {
advice "util::Queue" : os::Mutex lock;
➢ Protect enqueue() and dequeue() by a mutex object
pointcut sync_methods() = "% util::Queue::%queue(...)";

➢ To implement this, we need to advice execution(sync_methods()) && that(queue)


: around( util::Queue& queue ) {
– introduce a mutex variable into class Queue queue.lock.enter();
try {
– lock the mutex before the execution of enqueue() / dequeue() tjp->proceed();
}
– unlock the mutex after execution of enqueue() / dequeue() catch(...) {
queue.lock.leave();
throw;
➢ The aspect implementation should be exception safe! }
– in case of an exception, pending after advice is not called queue.lock.leave();
}
– solution: use around advice };

LockingMutex.ah

Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/37 Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/38

LockingMutex - Elements LockingMutex - Elements


aspect LockingMutex { aspect LockingMutex {
advice "util::Queue" : os::Mutex lock; advice "util::Queue" : os::Mutex lock;

pointcut sync_methods() = "% util::Queue::%queue(...)"; pointcut sync_methods() = "% util::Queue::%queue(...)";

advice execution(sync_methods()) && that(queue) advice execution(sync_methods()) && that(queue)


: around( util::Queue& queue ) { : around( util::Queue& queue ) {
queue.lock.enter(); queue.lock.enter(); Pointcuts can be named.
try { try { sync_methods describes all
tjp->proceed(); tjp->proceed();
} } methods that have to be
catch(...) { catch(...) { synchronized by the mutex
queue.lock.leave(); We introduce a mutex queue.lock.leave();
throw; member into class Queue throw;
} }
queue.lock.leave(); queue.lock.leave();
} }
}; };

LockingMutex.ah LockingMutex.ah

Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/39 Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/40
LockingMutex - Elements LockingMutex - Elements
aspect LockingMutex { aspect LockingMutex {
advice "util::Queue" : os::Mutex lock; advice "util::Queue" : os::Mutex lock;

pointcut sync_methods() = "% util::Queue::%queue(...)"; pointcut sync_methods() = "% util::Queue::%queue(...)";

advice execution(sync_methods()) && that(queue) advice execution(sync_methods()) && that(queue)


: around( util::Queue& queue ) { : around( util::Queue& queue ) {
queue.lock.enter(); queue.lock.enter();
try { try {
tjp->proceed(); tjp->proceed();
}
sync_methods is used to give }
catch(...) { around advice to the execution catch(...) {
queue.lock.leave(); of the methods queue.lock.leave(); By calling tjp->proceed() the
throw; throw; original method is executed
} }
queue.lock.leave(); queue.lock.leave();
} }
}; };

LockingMutex.ah LockingMutex.ah

Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/41 Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/42

LockingMutex – Lessons Learned Queue: A new Requirement


You have seen how to ...
➢ use named pointcuts I. Element counting We need Queue to be
– to increase readability of pointcut expressions synchronized on
interrupt level!
– to reuse pointcut expressions II. Errorhandling
➢ use around advice (signaling of errors by exceptions)
– to deal with exception safety
– to explicit invoke (or don't invoke) the III. Thread safety
original code by calling tjp->proceed() (synchronization by mutex variables)
➢ use wildcards in match expressions
– "% util::Queue::%queue(...)" matches both IV. Interrupt safety
enqueue() and dequeue() (synchronization on interrupt level)

Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/43 Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/44
Interrupt Safety: The Idea LockingIRQ1
aspect LockingIRQ {
➢ Scenario pointcut sync_methods() = "% util::Queue::%queue(...)";
pointcut kernel_code() = "% kernel::%(...)";
– Queue is used to transport objects between
kernel code (interrupt handlers) and application code advice call(sync_methods()) && !within(kernel_code()) : around() {
os::disable_int();
– If application code accesses the queue, try {
interrupts must be disabled first tjp->proceed();
}
– If kernel code accesses the queue, catch(...) {
interrupts must not be disabled os::enable_int();
throw;
}
➢ To implement this, we need to distinguish os::enable_int();
}
– if the call is made from kernel code, or };
– if the call is made from application code
LockingIRQ1.ah

Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/45 Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/46

LockingIRQ1 – Elements LockingIRQ1 – Elements


aspect LockingIRQ { aspect LockingIRQ {

pointcut sync_methods() = "% util::Queue::%queue(...)"; pointcut sync_methods() = "% util::Queue::%queue(...)";


pointcut kernel_code() = "% kernel::%(...)"; pointcut kernel_code() = "% kernel::%(...)";

advice call(sync_methods()) && !within(kernel_code()) : around() { advice call(sync_methods()) && !within(kernel_code()) : around() {
os::disable_int(); os::disable_int();
try { try {
tjp->proceed(); tjp->proceed();
} }
catch(...) { We define two pointcuts. One for the catch(...) { This pointcut expression matches any
os::enable_int(); methods to be synchronized and os::enable_int();
call to a sync_method that is not done
throw; throw;
} one for all kernel functions } from kernel_code
os::enable_int(); os::enable_int();
} }
}; };

LockingIRQ1.ah LockingIRQ1.ah

Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/47 Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/48
LockingIRQ1 – Result LockingIRQ1 – Problem
util::Queue queue; util::Queue queue;
void do_something() { void do_something() {
The pointcut within(kernel_code)
printf("do_something()\n"); main() printf("do_something()\n"); does not match any indirect calls
main()
queue.enqueue( new util::Item ); os::disable_int() queue.enqueue( new util::Item ); os::disable_int()
to sync_methods
} > Queue::enqueue(00320FD0) } > Queue::enqueue(00320FD0)
namespace kernel { < Queue::enqueue() namespace kernel { < Queue::enqueue()
void irq_handler() { os::enable_int() void irq_handler() { os::enable_int()
kernel::irq_handler()
printf("kernel::irq_handler()\n"); kernel::irq_handler()
printf("kernel::irq_handler()\n");
queue.enqueue(new util::Item); > Queue::enqueue(00321030) queue.enqueue(new util::Item); > Queue::enqueue(00321030)
do_something(); < Queue::enqueue() do_something(); < Queue::enqueue()
} do_something() } do_something()
} os::disable_int() } os::disable_int()
int main() { > Queue::enqueue(00321060) int main() { > Queue::enqueue(00321060)
printf("main()\n"); < Queue::enqueue() printf("main()\n"); < Queue::enqueue()
queue.enqueue(new util::Item); os::enable_int() queue.enqueue(new util::Item); os::enable_int()
kernel::irq_handler(); // irq back in main() kernel::irq_handler(); // irq back in main()
printf("back in main()\n"); os::disable_int() printf("back in main()\n"); os::disable_int()
queue.dequeue(); > Queue::dequeue() queue.dequeue(); > Queue::dequeue()
} < Queue::dequeue() returning 00320FD0 } < Queue::dequeue() returning 00320FD0
os::enable_int() os::enable_int()
main.cc main.cc
<Output> <Output>
Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/49 Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/50

LockingIRQ2 LockingIRQ2 – Elements


aspect LockingIRQ { aspect LockingIRQ {

pointcut sync_methods() = "% util::Queue::%queue(...)"; pointcut sync_methods() = "% util::Queue::%queue(...)";


pointcut kernel_code() = "% kernel::%(...)"; pointcut kernel_code() = "% kernel::%(...)";

advice execution(sync_methods()) advice execution(sync_methods())


&& !cflow(execution(kernel_code())) : around() { && !cflow(execution(kernel_code())) : around() {
os::disable_int(); os::disable_int();
try { try {
Solution This pointcut expression matches the
tjp->proceed(); tjp->proceed();
} Using the cflow pointcut function } execution of sync_methods if no
catch(...) { catch(...) { kernel_code is on the call stack.
os::enable_int(); os::enable_int(); cflow checks the call stack (control flow)
throw; throw;
} } at runtime.
os::enable_int(); os::enable_int();
} }
}; };

LockingIRQ2.ah LockingIRQ2.ah

Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/51 Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/52
LockingIRQ2 – Result LockingIRQ – Lessons Learned
util::Queue queue;
void do_something() { You have seen how to ...
printf("do_something()\n"); main()
queue.enqueue( new util::Item ); os::disable_int()
} > Queue::enqueue(00320FD0)
namespace kernel { < Queue::enqueue() ➢ restrict advice invocation to a specific calling context
void irq_handler() { os::enable_int()
kernel::irq_handler()
printf("kernel::irq_handler()\n");
queue.enqueue(new util::Item); > Queue::enqueue(00321030)
do_something(); < Queue::enqueue() ➢ use the within(...) and cflow(...) pointcut functions
} do_something()
} > Queue::enqueue(00321060) – within is evaluated at compile time and returns all code
int main() { < Queue::enqueue() joinpoints of a class' or namespaces lexical scope
printf("main()\n"); back in main()
queue.enqueue(new util::Item); os::disable_int()
kernel::irq_handler(); // irq > Queue::dequeue() – cflow is evaluated at runtime and returns all joinpoints
printf("back in main()\n"); < Queue::dequeue() returning 00320FD0
queue.dequeue(); os::enable_int()
where the control flow is below a specific code joinpoint
}

main.cc
<Output>
Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/53 Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/54

AspectC++: A First Summary AspectC++: Advanced Concepts


➢ The Queue example has presented the most ➢ Join Point API
important features of the AspectC++ language  provides a uniform interface to the aspect invocation context,
 aspect, advice, joinpoint, pointcut expression, both at runtime and compile-time
pointcut function, ... ➢ Abstract Aspects and Aspect Inheritance
➢ Additionaly, AspectC++ provides some more  comparable to class inheritance, aspect inheritance allows to
advanced concepts and features reuse parts of an aspect and overwrite other parts
 to increase the expressive power of aspectual code ➢ Generic Advice
 to write broadly reusable aspects  exploits static type information in advice code
 to deal with aspect interdependence and ordering ➢ Aspect Ordering
➢ In the following, we give a short overview on  allows to specify the invocation order of multiple aspects
these advanced language elements ➢ Aspect Instantiation
 allows to implement user-defined aspect instantiation models

Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/55 Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/56
The Joinpoint API The Join Point API (Excerpt)
Types (compile-time) Values (runtime)
➢ Inside an advice body, the current joinpoint context
is available via the implicitly passed tjp variable: // object type (initiator)
That
// pointer to the object initiating a call
That* that()
advice ... { // object type (receiver) // pointer to the object that is target of a call
struct JoinPoint { Target Target* target()
... // result type of the affected function // pointer to the result value
} *tjp; // implicitly available in advice code Result Result* result()
... // type of the i'th argument of the affected // typed pointer the i'th argument value of a
} // function (with 0 <= i < ARGS) // function call (compile-time index)
Arg<i>::Type Arg<i>::ReferredType* arg()
➢ You have already seen how to use tjp, to ... Arg<i>::ReferredType
// pointer the i'th argument value of a
// function call (runtime index)
 execute the original code in around advice with tjp->proceed() Consts (compile-time) void* arg( int i )
// textual representation of the joinpoint
➢ The joinpoint API provides a rich interface // number of arguments
ARGS
// (function/class name, parameter types...)
static const char* signature()
 to expose context independently of the aspect target // unique numeric identifier for this join point // executes the original joinpoint code
JPID // in an around advice
 this is especially useful in writing reusable aspect code // numeric identifier for the type of this join void proceed()
// point (AC::CALL, AC::EXECUTION, ...) // returns the runtime action object
JPTYPE AC::Action& action()
Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/57 Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/58

Abstract Aspects and Inheritance Abstract Aspects and Inheritance


The abstract locking aspect declares
➢ Aspects can inherit from other aspects... #include "mutex.h" two pure virtual pointcuts and uses
 Reuse aspect definitions aspect LockingA { the joinpoint API for an context-
pointcut virtual sync_classes() = 0;
 Override methods and pointcuts pointcut virtual sync_methods() = 0;
independent advice implementation.

➢ Pointcuts can be pure virtual advice sync_classes() : os::Mutex lock;


 Postpone the concrete definition to derived aspects advice execution(sync_methods()) : around() {
 An aspect with a pure virtual pointcut is called abstract aspect tjp->that()->lock.enter();
try {
tjp->proceed();
➢ Common usage: Reusable aspect implementations }
catch(...) {
 Abstract aspect defines advice code, but pure virtual pointcuts tjp->that()->lock.leave(); #include "LockingA.ah"
 Aspect code uses the joinpoint API to expose context throw;
aspect LockingQueue : public LockingA {
}
 Concrete aspect inherits the advice code and overrides pointcuts tjp->that()->lock.leave(); pointcut sync_classes() =
} "util::Queue";
}; pointcut sync_methods() =
"% util::Queue::%queue(...)";
};
LockingA.ah LockingQueue.ah
Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/59 Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/60
Abstract Aspects and Inheritance Generic Advice
#include "mutex.h" Uses static JP-specific type information in advice code
aspect LockingA {  in combination with C++ overloading
pointcut virtual sync_classes() = 0;
pointcut virtual sync_methods() = 0;  to instantiate C++ templates and template meta-programs
advice sync_classes() : os::Mutex lock;
The concrete locking aspect
advice execution(sync_methods()) : around() { derives from the abstract aspect
tjp->that()->lock.enter(); and overrides the pointcuts.
try {
tjp->proceed(); ... operator <<(..., int)
} aspect TraceService {
catch(...) {
#include "LockingA.ah"
advice call(...) : after() {
tjp->that()->lock.leave();
... ... operator <<(..., long)
throw;
}
aspect LockingQueue : public LockingA { cout << *tjp->result();
pointcut sync_classes() =
tjp->that()->lock.leave(); }
} "util::Queue"; ... operator <<(..., bool)
pointcut sync_methods() = };
};
"% util::Queue::%queue(...)";
};
... operator <<(..., Foo)
LockingA.ah LockingQueue.ah
Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/61 Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/62

Generic Advice Aspect Ordering


Uses static JP-specific type information in advice code ➢ Aspects should be independent of other aspects
in combination with C++ overloading
  However, sometimes inter-aspect dependencies are unavoidable
 to instantiate C++ templates and template meta-programs Example: Locking should be activated before any other aspects
Resolves to the statically typed return value 

 no runtime type checks are needed ➢ Order advice


 unhandled types are detected at compile-time
 functions can be inlined
 The aspect order can be defined by order advice
advice pointcut-expr : order(high, ..., low)
... operator <<(..., int)  Different aspect orders can be defined for different pointcuts
aspect TraceService {
advice call(...) : after() {
➢ Example
... ... operator <<(..., long)
cout << *tjp->result(); advice "% util::Queue::%queue(...)"
} : order( "LockingIRQ", "%" && !"LockingIRQ" );
... operator <<(..., bool)
};

... operator <<(..., Foo)


Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/63 Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/64
Aspect Instantiation Summary
➢ Aspects are singletons by default ➢ AspectC++ facilitates AOP with C++
 aspectof() returns pointer to the one-and-only aspect instance  AspectJ-like syntax and semantics
➢ By overriding aspectof() this can be changed ➢ Full obliviousness and quantification
 e.g. one instance per client or one instance per thread  aspect code is given by advice
 joinpoints are given declaratively by pointcuts
aspect MyAspect { Example of an user-  implementation of crosscutting concerns is fully
// .... defined aspectof() encapsulated in aspects
static MyAspect* aspectof() { implementation for
static __declspec(thread) MyAspect* theAspect;
per-thread aspect
➢ Good support for reusable and generic aspect code
if( theAspect == 0 )
theAspect = new MyAspect; instantiation by using  aspect inheritance and virtual pointcuts
return theAspect; thread-local storage.  rich joinpoint API
}
}; (Visual C++)
MyAspect.ah And what about tool support?

Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/65 Aspect C++ © 2005 Daniel Lohmann and Olaf Spinczyk III/66
Aspect-Oriented Programming Overview
with
C++ and AspectC++ ➢ ac++ compiler
– open source and base of the other presented tools
AOSD 2005 Tutorial
➢ ag++ wrapper
– easy to use wrapper around g++ for make-based projects
➢ AspectC++ Add-In for Microsoft® Visual Studio®
– commercial product by pure-systems GmbH

Part IV – Tool Support ➢ AspectC++ plugin for Eclipse®


– sophisticated environment for AspectC++ development

➔ demonstration with the tutorial CD


Tool Support © 2005 Daniel Lohmann and Olaf Spinczyk IV/1 Tool Support © 2005 Daniel Lohmann and Olaf Spinczyk IV/2

About ac++ Aspect Transformation


➢ Available from www.aspectc.org aspect Transform {
advice call("% foo()") : before() {
– Linux, Win32, Solaris, MacOS X binaries + source (GPL) printf("before foo call\n");
}
– documentation: Compiler Manual, Language Reference, ... advice execution("% C::%()") : after()
{
printf(tjp->signature ());
➢ Transforms AspectC++ to C++ code } class Transform {
– machine code is created by the back-end (cross-)compiler }; static Transform __instance;
Transform.ah // ...
– supports g++ and Visual C++ specific language extensions void __a0_before () {
printf ("before foo call\n");
}
➢ Current version: 1.0 template<class JoinPoint>
void __a1_after (JoinPoint *tjp) {
– stable printf (tjp->signature ());
– (almost) feature-complete }
};
– no optimizations for compilation speed, yet
Transform.ah'
Tool Support © 2005 Daniel Lohmann and Olaf Spinczyk IV/3 Tool Support © 2005 Daniel Lohmann and Olaf Spinczyk IV/4
Aspect Transformation Aspect Transformation
One global aspect
aspect Transform { Aspects are transformed aspect Transform {
instance is created by
advice call("% foo()") : before() { into ordinary classes advice call("% foo()") : before() {
printf("before foo call\n"); printf("before foo call\n"); default
} }
advice execution("% C::%()") : after() advice execution("% C::%()") : after()
{ {
printf(tjp->signature ()); printf(tjp->signature ());
} class Transform { } class Transform {
}; static Transform __instance; }; static Transform __instance;
Transform.ah // ... Transform.ah // ...
void __a0_before () { void __a0_before () {
printf ("before foo call\n"); printf ("before foo call\n");
} }
template<class JoinPoint> template<class JoinPoint>
void __a1_after (JoinPoint *tjp) { void __a1_after (JoinPoint *tjp) {
printf (tjp->signature ()); printf (tjp->signature ());
} }
}; };

Transform.ah' Transform.ah'
Tool Support © 2005 Daniel Lohmann and Olaf Spinczyk IV/5 Tool Support © 2005 Daniel Lohmann and Olaf Spinczyk IV/6

Aspect Transformation Aspect Transformation


aspect Transform { Advice becomes a aspect Transform { “Generic Advice”
advice call("% foo()") : before() { member function advice call("% foo()") : before() {
printf("before foo call\n"); printf("before foo call\n"); becomes a template
} } member function
advice execution("% C::%()") : after() advice execution("% C::%()") : after()
{ {
printf(tjp->signature ()); printf(tjp->signature ());
} class Transform { } class Transform {
}; static Transform __instance; }; static Transform __instance;
Transform.ah // ... Transform.ah // ...
void __a0_before () { void __a0_before () {
printf ("before foo call\n"); printf ("before foo call\n");
} }
template<class JoinPoint> template<class JoinPoint>
void __a1_after (JoinPoint *tjp) { void __a1_after (JoinPoint *tjp) {
printf (tjp->signature ()); printf (tjp->signature ());
} }
}; };

Transform.ah' Transform.ah'
Tool Support © 2005 Daniel Lohmann and Olaf Spinczyk IV/7 Tool Support © 2005 Daniel Lohmann and Olaf Spinczyk IV/8
Joinpoint Transformation Joinpoint Transformation
int main() { int main() { the function call is replaced by
foo(); foo();
return 0; return 0;
a call to a wrapper function
} }
main.cc main.cc
int main() { int main() {
struct __call_main_0_0 { struct __call_main_0_0 {
static inline void invoke (){ static inline void invoke (){
AC::..._a0_before (); AC::..._a0_before ();
::foo(); ::foo();
} }
}; };
__call_main_0_0::invoke (); __call_main_0_0::invoke ();
return 0; return 0;
} }

main.cc' main.cc'

Tool Support © 2005 Daniel Lohmann and Olaf Spinczyk IV/9 Tool Support © 2005 Daniel Lohmann and Olaf Spinczyk IV/10

Joinpoint Transformation Translation Modes


int main() {
foo();
a local class invokes the advice ➢ Whole Program Transformation-Mode
return 0;
code for this joinpoint
– e.g. ac++ -p src -d gen -e cpp -Iinc -DDEBUG
}
main.cc – transforms whole directory trees
int main() { – generates manipulated headers, e.g. for libraries
struct __call_main_0_0 {
static inline void invoke (){ – can be chained with other whole program
AC::..._a0_before ();
::foo();
transformation tools
}
};
➢ Single Translation Unit-Mode
__call_main_0_0::invoke ();
return 0; – e.g. ac++ -c a.cc -o a-gen.cc -p .
}
– easier integration into build processes
main.cc'

Tool Support © 2005 Daniel Lohmann and Olaf Spinczyk IV/11 Tool Support © 2005 Daniel Lohmann and Olaf Spinczyk IV/12
Tool Demos Summary
➢ Tool support for AspectC++ programming is based
on the ac++ command line compiler
– AspectC++ Add-In for Microsoft® Visual Studio®
– full “obliviousness and quantification”
– delegates the binary code generation to your
 by pure-systems GmbH (www.pure-systems.com) favorite compiler
➢ Commercial and a non-commercial
®
– AspectC++ plugin for Eclipse IDE integration is available
– Microsoft® Visual Studio®
 sophisticated environement for AspectC++ development – Eclipse®

Tool Support © 2005 Daniel Lohmann and Olaf Spinczyk IV/13 Tool Support © 2005 Daniel Lohmann and Olaf Spinczyk IV/14
Aspect-Oriented Programming AspectC++ in Practice - Examples
with
C++ and AspectC++ ➢ Applying the observer protocol
– Example: a typical scenario for the widely used observer pattern
AOSD 2004 Tutorial
– Problem: implementing observer requires several
design and code transformations

➢ Errorhandling in legacy code


– Example: a typical Win32 application
– Problem: errorhandling often “forgotten” as too much of a bother
Part V – Examples
➢ Product line development
– Example: an embedded weather station software family
– Problem: optional crosscutting concerns in optional components
(a typical case for the #ifdef hell)

Examples V/1 Examples V/2

Observer Pattern: Scenario Observer Pattern: Implementation

IObserver observers ISubject


update (in s : ISubject) updateAll()

DigitalClock AnalogClock ClockTimer DigitalClock AnalogClock ClockTimer


Draw() Draw() GetHour() : int Draw() Draw() GetHour() : int
SetTime (in h : int , in m : int, in s : int ) update (in s) update (in s) SetTime (in h : int , in m : int, in s : int )
Tick() Tick()

update on
change
Examples V/3 Examples V/4
Observer Pattern: Problem Solution: Generic Observer Aspect
aspect ObserverPattern {
The 'Observer Protocol' Concern... ...
public:
struct ISubject {};
IObserver observers ISubject struct IObserver {
update (in s : ISubject) updateAll() virtual void update (ISubject *) = 0;
};
pointcut virtual observers() = 0;
pointcut virtual subjects() = 0;
pointcut virtual subjectChange() = execution( "% ...::%(...)"
&& !"% ...::%(...) const" ) && within( subjects() );
advice observers () : baseclass( IObserver );
advice subjects() : baseclass( ISubject );
DigitalClock AnalogClock ClockTimer advice subjectChange() : after () {
Draw() Draw() GetHour() : int ISubject* subject = tjp->that();
update (in s) update (in s) SetTime (in h : int , in m : int, in s : int ) updateObservers( subject );
Tick() }
void updateObservers( ISubject* subject ) { ... }
void addObserver( ISubject* subject, IObserver* observer ) { ... }
...crosscuts the module structure void remObserver( ISubject* subject, IObserver* observer ) { ... }
};
Examples V/5 Examples V/6

Solution: Generic Observer Aspect Solution: Generic Observer Aspect


aspect ObserverPattern { aspect ObserverPattern {
... ...
public: Interfaces for the public: abstract pointcuts that
struct ISubject {}; subject/observer roles struct ISubject {}; define subjects/observers
struct IObserver { struct IObserver {
virtual void update (ISubject *) = 0; virtual void update (ISubject *) = 0; (need to be overridden by a
}; }; derived aspect)
pointcut virtual observers() = 0; pointcut virtual observers() = 0;
pointcut virtual subjects() = 0; pointcut virtual subjects() = 0;
pointcut virtual subjectChange() = execution( "% ...::%(...)" pointcut virtual subjectChange() = execution( "% ...::%(...)"
&& !"% ...::%(...) const" ) && within( subjects() ); && !"% ...::%(...) const" ) && within( subjects() );
advice observers () : baseclass( IObserver ); advice observers () : baseclass( IObserver );
advice subjects() : baseclass( ISubject ); advice subjects() : baseclass( ISubject );
advice subjectChange() : after () { advice subjectChange() : after () {
ISubject* subject = tjp->that(); ISubject* subject = tjp->that();
updateObservers( subject ); updateObservers( subject );
} }
void updateObservers( ISubject* subject ) { ... } void updateObservers( ISubject* subject ) { ... }
void addObserver( ISubject* subject, IObserver* observer ) { ... } void addObserver( ISubject* subject, IObserver* observer ) { ... }
void remObserver( ISubject* subject, IObserver* observer ) { ... } void remObserver( ISubject* subject, IObserver* observer ) { ... }
}; };
Examples V/7 Examples V/8
Solution: Generic Observer Aspect Solution: Generic Observer Aspect
aspect ObserverPattern {
virtual pointcut defining all aspect ObserverPattern {
... state-changing methods. ... Introduction of the role
public: public: interface as additional
struct ISubject {}; (Defaults to the execution of any struct ISubject {};
struct IObserver { non-const method in subjects) struct IObserver { baseclass into
virtual void update (ISubject *) = 0; virtual void update (ISubject *) = 0; subjects / observers
}; };
pointcut virtual observers() = 0; pointcut virtual observers() = 0;
pointcut virtual subjects() = 0; pointcut virtual subjects() = 0;
pointcut virtual subjectChange() = execution( "% ...::%(...)" pointcut virtual subjectChange() = execution( "% ...::%(...)"
&& !"% ...::%(...) const" ) && within( subjects() ); && !"% ...::%(...) const" ) && within( subjects() );
advice observers () : baseclass( IObserver ); advice observers () : baseclass( IObserver );
advice subjects() : baseclass( ISubject ); advice subjects() : baseclass( ISubject );
advice subjectChange() : after () { advice subjectChange() : after () {
ISubject* subject = tjp->that(); ISubject* subject = tjp->that();
updateObservers( subject ); updateObservers( subject );
} }
void updateObservers( ISubject* subject ) { ... } void updateObservers( ISubject* subject ) { ... }
void addObserver( ISubject* subject, IObserver* observer ) { ... } void addObserver( ISubject* subject, IObserver* observer ) { ... }
void remObserver( ISubject* subject, IObserver* observer ) { ... } void remObserver( ISubject* subject, IObserver* observer ) { ... }
}; };
Examples V/9 Examples V/10

Solution: Generic Observer Aspect Solution: Putting Everything Together


aspect ObserverPattern {
... After advice to update
public: observers after
struct ISubject {};
execution of a state- Applying the Generic Observer Aspect to the clock example
struct IObserver {
virtual void update (ISubject *) = 0; changing method aspect ClockObserver : public ObserverPattern {
};
// define the participants
pointcut virtual observers() = 0; pointcut subjects() = "ClockTimer";
pointcut virtual subjects() = 0; pointcut observers() = "DigitalClock"||"AnalogClock";
pointcut virtual subjectChange() = execution( "% ...::%(...)" public:
&& !"% ...::%(...) const" ) && within( subjects() ); // define what to do in case of a notification
advice observers() : void update( ObserverPattern::ISubject* s ) {
advice observers () : baseclass( IObserver );
Draw();
advice subjects() : baseclass( ISubject );
}
advice subjectChange() : after () { };
ISubject* subject = tjp->that();
updateObservers( subject );
}
void updateObservers( ISubject* subject ) { ... }
void addObserver( ISubject* subject, IObserver* observer ) { ... }
void remObserver( ISubject* subject, IObserver* observer ) { ... }
};
Examples V/11 Examples V/12
Observer Pattern: Conclusions Errorhandling in Legacy Code: Scenario
LRESULT WINAPI WndProc( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam ) {
HDC dc = NULL; PAINTSTRUCT ps = {0};
➢ Applying the observer protocol is now very easy! switch( nMsg ) {
case WM_PAINT: A typical Win32
– all necessary transformations are performed by the generic aspect dc = BeginPaint( hWnd, &ps );
... application
– programmer just needs to define participants and behaviour EndPaint(hWnd, &ps);
break;
– multiple subject/observer relationships can be defined ...
}}

int WINAPI WinMain( ... ) {


➢ More reusable and less error-prone component code HANDLE hConfigFile = CreateFile( "example.config", GENERIC_READ, ... );

– observer no longer “hard coded” into the desing and code WNDCLASS wc = {0, WndProc, 0, 0, ... , "Example_Class"};
RegisterClass( &wc );
HWND hwndMain = CreateWindowEx( 0, "Example_Class", "Example", ... );
– no more forgotten calls to update() in subject classes UpdateWindow( hwndMain );

MSG msg;
➢ Full source code on Tutorial CD while( GetMessage( &msg, NULL, 0, 0 ) ) {
TranslateMessage( &msg );
DispatchMessage( &msg );
}
return 0;
Examples V/13 Examples
} V/14

Errorhandling in Legacy Code: Scenario Win32 Errorhandling: Goals


LRESULT WINAPI WndProc( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam ) {
HDC dc = NULL; PAINTSTRUCT ps = {0};
➢ Detect failed calls of Win32 API functions
switch( nMsg ) {
case WM_PAINT: These Win32 API  by giving after advice for any call to a Win32 function
dc = BeginPaint( hWnd, &ps );
... functions may fail! ➢ Throw a helpful exception in case of a failure
EndPaint(hWnd, &ps);
break;
 describing the exact circumstances and reason of the failure
...
}}
Problem: Win32 failures are indicated by a “magic” return value
int WINAPI WinMain( ... ) {
HANDLE hConfigFile = CreateFile( "example.config", GENERIC_READ, ... );
 magic value to compare against depends on the return type of the function
 error reason (GetLastError()) only valid in case of a failure
WNDCLASS wc = {0, WndProc, 0, 0, ... , "Example_Class"};
RegisterClass( &wc );
HWND hwndMain = CreateWindowEx( 0, "Example_Class", "Example", ... ); return type magic value
UpdateWindow( hwndMain );
BOOL FALSE
MSG msg;
while( GetMessage( &msg, NULL, 0, 0 ) ) { ATOM (ATOM) 0
TranslateMessage( &msg );
DispatchMessage( &msg );
HANDLE INVALID_HANDLE_VALUE or NULL
} HWND NULL
return 0;
Examples
} V/15 Examples V/16
Detecting the failure: Generic Advice Describing the failure: Generative Advice
template <int I> struct ArgPrinter {
template <class JP> static void work (JP &tjp, ostream &s) {
ArgPrinter<I–1>::work (tjp, s);
bool isError(ATOM); s << “, “ << *tjp. template arg<I-1>();
}
};
advice call(win32API ()) :
after () { bool isError(BOOL);
if (isError (*tjp->result())) advice call(win32API ()) : after () {
// throw an exception
// throw an exception
bool isError(HANDLE); ostringstream s;
} DWORD code = GetLastError();
s << “WIN32 ERROR ” << code << ...
bool isError(HWND); << win32::GetErrorText( code ) << ... <<
<< tjp->signature() << “WITH: ” << ...;
ArgPrinter<JoinPoint::ARGS>::work (*tjp, s);
...
throw win32::Exception( s.str() );
}
Examples V/17 Examples V/18

Reporting the Error Errorhandling in Legacy Code: Conclusions


LRESULT WINAPI WndProc( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam ) {
HDC dc = NULL; PAINTSTRUCT ps = {0};
➢ Easy to apply errorhandling for Win32 applications
switch( nMsg ) {
case WM_PAINT:
dc = BeginPaint( hWnd, &ps );
– previously undetected failures are reported by exceptions
...
EndPaint(hWnd, &ps); – rich context information is provided
break;
...
}}
➢ Uses advanced AspectC++ techniques
int WINAPI WinMain( ... ) {
HANDLE hConfigFile = CreateFile( "example.config", GENERIC_READ, ... );
– error detection by generic advice
WNDCLASS wc = {0, WndProc, 0, 0, ... , "Example_Class"};
RegisterClass( &wc ); – context propagation by generative advice
HWND hwndMain = CreateWindowEx( 0, "Example_Class", "Example", ... );
UpdateWindow( hwndMain );

MSG msg;
while( GetMessage( &msg, NULL, 0, 0 ) ) {
➢ Full source code on tutorial CD
TranslateMessage( &msg );
DispatchMessage( &msg );
}
return 0;
Examples
} V/19 Examples V/20
Aspect-Oriented Programming Pros and Cons
with
C++ and AspectC++ AOP with pure C++
+ no special tool required
AOSD 2005 Tutorial – requires in-depth understanding of C++ templates
– lack of “obliviousness”
the component code has to be aspect-aware
– lack of “quantification”
no pointcut concept, no match expressions
AspectC++
Part VI – Summary +
+
the ac++ compiler transforms AspectC++ into C++
various supported joinpoint types, e.g. execution and calls
+ built-in support for advanced AOP concepts:
cflow, joinpoint-API
– longer compilation times

Summary © 2005 Daniel Lohmann and Olaf Spinczyk VI-1 Summary © 2005 Daniel Lohmann and Olaf Spinczyk VI-2

Summary – This Tutorial ... Future Work – Roadmap


➢ showed basic techniques for AOP with pure C++ ➢ Parser improvements
– using templates to program generic wrapper code – full template support
– using action classes to encapsulate the “proceed-code” – speed optimization
– using namespaces to substitute types transparently – full g++ 3.x and Visual C++ compatibility
➢ introduced the AspectC++ language extension for C++ ➢ Language design/weaver
– AspectJ-like language extension – weaving in templates
– ac++ transforms AspectC++ into C++ – advice for object access (set/get pointcut functions)
– supports AOP even in resource constrained environments – advice for object instantiations
➢ demonstrated the AspectC++ tools ➢ Tools
➢ discussed the pros and cons of each approach – dependency handling

Summary © 2005 Daniel Lohmann and Olaf Spinczyk VI-3 Summary © 2005 Daniel Lohmann and Olaf Spinczyk VI-4
Thank you for your attention!

Summary © 2005 Daniel Lohmann and Olaf Spinczyk VI-5

You might also like