Aspects and Polymorphism in Aspectj
Total Page:16
File Type:pdf, Size:1020Kb
Aspects and Polymorphism in AspectJ Erik Ernst David H. Lorenz Dept. of Computer Science, College of Computer & Information Science, University of Aarhus Northeastern University Abogade˚ 34, DK8200 Arhus˚ N 360 Huntington Avenue 161 CN Denmark Boston, Massachusetts 02115 USA [email protected] [email protected] ABSTRACT ¢ Polymorphic access: A name denotes an object whose dy- There are two important points of view on inclusion or subtype namic type is known only by an upper bound. For example, polymorphism in object-oriented programs, namely polymorphic the predefined reference self in a method in a class C de- access and dynamic dispatch. These features are essential for object- notes an instance of C or some subclass of C. The essence is oriented programming, and it is worthwhile to consider whether that the same code can operate on differently shaped objects they are supported in aspect-oriented programming (AOP). In AOP, because they all satisfy certain constraints (possibly made pieces of crosscutting behavior are extracted from the base code explicit in a statically declared type). and localized in aspects, losing as a result their polymorphic capa- ¢ Dynamic dispatch: When accessing an object polymorphi- bilities while introducing new and unexplored issues. In this paper, cally, a message-send may be resolved by late binding, i.e., we explore what kinds of polymorphism AOP languages should it may call different method implementations for different support, using AspectJ as the basis for the presentation. The results dynamic receiver types. The essence is that the meaning of are not exclusive to AspectJ—aspectual polymorphism may make a name (the method selector) is determined by dynamically aspects in any comparable AOSD language more expressive and selecting the “best” definition from a set of different avail- reusable across programs, while preserving safety. able definitions, namely all the method implementations in the dynamic class of the receiver and its superclasses. 1. INTRODUCTION There are two important points of view on inclusion or subtype polymorphism in object-oriented programs, namely polymorphic In short, inclusion polymorphism is characterized by invariance in access and dynamic dispatch (Figure 1). an “early” phase (e.g., a call site contains one particular message send foo; or an object £ contains a known set of features), and by dynamic variance in a “late” phase (e.g., considering all the Polymorphism possible implementations of foo for that call site; or all the pos- sible additional features of £ ). Late binding of methods provides the flexibility of executing different behaviors at the same call site, Ad hoc Universal while preserving the safety of always executing a behavior that is appropriate for the actual receiver object. For object access, we get the flexibility of being able to add new features, and the safety guarantee that known features will indeed be present dynamically. Coercion Overloading Inclusion Parametric In this paper, we seek a similar kind of safe flexibility by means of polymorphism in connection with aspects. Polymorphic Dynamic Access Dispatch Inclusion polymorphism is a kind of universal polymorphism, which means that the set of possible forms in the late phase is open- Figure 1: Polymorphism ended [7]. In contrast, in ad-hoc polymorphism, the set of possible forms is determined in the early phase, and one specific form is se- lected. For example, an overloaded operation also simultaneously Supported in part by the National Science Foundation (NSF) un- denotes more than one function [21]. However, unlike dynamic dis- der Grant No. CCR-0098643 and CCR-0204432, and by the Insti- tute for Complex Scientific Software at Northeastern University. patch, overloading is resolved at compile time and hence is a form of ad-hoc polymorphism. Permission to make digital or hard copies of all or part of this work for In AspectJ [27, 25], object-oriented polymorphism is supported in personal or classroom use is granted without fee provided that copies the sense that the Java [3] programming language supports poly- are not made or distributed for profit or commercial advantage and that morphism, and AspectJ is a superset of Java. Similar connections copies bear this notice and the full citation on the first page. To copy would typically exist with other AOSD approaches. The support otherwise, to republish, to post on servers or to redistribute to lists, for polymorphism in connection with aspects is essentially ad-hoc. requires prior specific permission and/or a fee. AOSD 2003 Boston, MA USA For example, one can write a single implementation of an aspect, ¡ c ACM 2003 1581136609/03/002...$5.00 which displays polymorphic behavior in different join points. Con- 150 sider the abstract aspect SimpleTracing in Listing 1. 1 and this means that the advice code will polymorphically access the receiver, p, of the intercepted invocation of setX. Listing 1: SimpleTracing.java However, all these examples of polymorphism are “inherited” from package aspect;2 import org.aspectj.lang.JoinPoint; the base language. Imagine a base language without polymor- abstract aspect SimpleTracing { phism, and they would all evaporate. abstract pointcut tracePoints(); before(): !within(aspect..*) && tracePoints() { Even the notion of an abstract pointcut and associated definitions trace(thisJoinPoint); of concrete pointcuts is not truly polymorphic in the same sense } as object-oriented methods. It is true that advice code such as the protected abstract void trace(JoinPoint jp); } invocation of trace in Listing 1 is executed depending on a point- cut whose concrete definition is not known in SimpleTracing. In other words, it is not known in SimpleTracing when this ad- The thisJoinPoint pseudo variable (and the related pseudo vari- vice code will be executed. But for each location in the program able thisJoinPointStaticPart) is bound to an object repre- where this advice may actually be enabled, it will be considered senting the current join point, thus providing access to dynamic in context of a concrete subaspect of SimpleTracing for which (respectively static) information about that join point. This object tracePoints can be checked statically—e.g., can be queried with methods such as Listing 3: PointTracing.java thisJoinPoint.getThis() aspect PointTracing extends ExecutingObjectTracing { pointcut tracePoints(): or execution(* Point+.setX(..)); } thisJoinPointStaticPart.getSignature() .getDeclaringType().getName() —“is this an invocation of C.setX where C is Point or a subclass which will give different outcomes depending on the actual join thereof?” Note that even with dynamic pointcuts, e.g., cflow, it is point. This is because the pointcut (and hence the aspect) is ab- known statically that it is a cflow pointcut, with a known specifi- stract, which means that an actual aspect using the given before- cation, and the dynamic part is only determining whether a given advice would be a subaspect of SimpleTracing in which the point- expression is true or not. cut tracePoints has been made concrete, and the method trace has been implemented. Hence, an execution of the before-advice 2. ADHOC POLYMORPHISM IN ASPECTJ would happen in context of an aspect instance whose type is only There are several points worth noting about polymorphism in As- known by an upper bound, and thisJoinPoint is only known to pectJ. be a join point. 2.1 Extending an aspect Moreover, an aspect can define abstract or concrete methods for It is possible to extend an abstract aspect, but not a concrete one. subaspects to redefine or use, e.g., The concrete aspect PointTracing (Listing 3) extends the ab- stract aspect ExecutingObjectTracing (Listing 2). However, Listing 2: ExecutingObjectTracing.java PointTracing cannot be further extended. This is actually a mi- abstract aspect ExecutingObjectTracing nor limitation that can be explained as an enforcement of the “ab- extends SimpleTracing { stract superclass rule” [20], i.e., the rule that only the leaves of an protected void trace(JoinPoint jp) { inheritance hierarchy can be concrete. Every aspect hierarchy can System.out.println("Executing object: " be transformed into one in which all super-aspects are abstract, al- + jp.getThis()); 3 } though this is not typically required by programming languages. } 2.2 Overriding a pointcut designator It is possible to redefine concrete pointcuts in the subaspect. For Finally, an advice and a pointcut may take arguments such as the example, the abstract aspect ReturnValueTracing in Listing 4, receiver object, e.g., Listing 4: ReturnValueTracing.java after(Point p, int nval): target(p) abstract public aspect ReturnValueTracing && args(nval) extends ExecutingObjectTracing { && call(void Point.setX(int)) { pointcut tracePoints(): call(*.new (..)); System.out.println("x in " + p after() returning (Object o): tracePoints() { + " is now set to " + nval + "."); System.out.println("Return: " + o); } } } 1To avoid explaining AspectJ basics we will assume knowledge of [25] and use some examples similar to the ones in that paper. In 3For example, the Sather programming language separates classes specific discussions about properties of AspectJ we are referring to and types strictly, and supports only the `insert-new-super' for version 1.0.6 types. However, the treatment of classes in Sather does not en- 2For the rest of the paper we will assume that all aspects are defined force a strict abstract superclass rule. Even in Sather it is possible in this package. to inherit from