![Aspect-Oriented Programming Is Quantification and Oblivi- Ousness](https://data.docslib.org/img/3a60ab92a6e30910dab9bd827208bcff-1.webp)
Aspect-Oriented Programming is Quantification and Oblivi- ousness Robert E. Filman Daniel P. Friedman RIACS Computer Science Department NASA Ames Research Center Indiana University Moffett Field, CA 94035 Bloomington, IN 47405 [email protected] [email protected] Abstract This paper proposes that the distinguishing characteristic of Aspect-Oriented Programming (AOP) systems is that they allow programming by making quantified programmatic assertions over programs written by programmers oblivious to such assertions. Thus, AOP systems can be analyzed with respect to three critical dimensions: the kinds of quantifications allowed, the nature I,,,._. the actions that can be asserted, and the mechanism for combining base-level actions with as- serted actions. Consequences of this perspective are the recognition that certain systems are not AOP and that some mechanisms are expressive enough to allow programming an AOP system within them. A corollary is that while AOP can be applied to Object-Oriented Programming, it is an independent concept applicable to other programming styles. 1. Introduction This paper is about Aspect-Oriented Programming (AOP) qua programming language. We are interested in determining what makes a language AOP. This work was prompted by a question from Tzilla Elrad, who asked whether event-based, publish and subscribe (EBPS) (for example, [9]) is AOP. After all, in a publish-and-subscribe system, separate concerns can be realized by subscribing to the events of interest to those concerns. In thinking about that question, we have come to the belief that two properties, quantification and obliviousness, are necessary for Aop.t Understanding these relationships clarifies the variety of possible AOP languages. It demonstrates why some systems that might seem to be AOP are not, and why some systems are environments in which one might easily build an AOP system. 2. Local and unitary statements Programming languages are about writing a structure of statements that a compilation or interpre- tation process will elaborate as a series of primitive directions. (The directions themselves will be a finite text, though their interpretation may be unbounded.) The earliest computer (machine lan- guage) programs had a strict correspondence between the program text and the execution pattern. Generally, each programming language statement was both unitary and local--unitary in that it ended up having effect in precisely one place in the elaborated program, and local in that it is al- most always proximate to its neighboring statements, z ' We are addressing the structural essence of AOP here, not it's application--somewhat similar to the dif- ference between defining Object-Oriented Programming (OOP) systems in termsofpolymorphic methods and inheritance, versus waxing euphoric aboutobjects as the appropriateway to model the world. ' A minor exception to locality and unitarity was the introduction of types. Type declarationscan have non- local and quantified effects such as type-coercion and type consistency checks. Types in conventional lan- guages are thus an example of a built-in separate concern. The history (of this part) of programming languages has been about moving away from purely local and unitary languages--about mechanisms that let the programmer separate concepts prag- matically, instead of being tied to saying things just where they happen. The first exceptions to locality were subprograms (i.e., procedures, subroutines, functions.) Subprograms were a great invention, enabling abstracting out some behavior to someplace else. They have all the virtues of separating concerns. For example, expertise in, say, Runge-Kutta methods could be centered in the writer of the Runge-Kutta library. The application programmers would be users of that li- brary. They still had to know something about "Runge-Kutta (when it was useful, how to invoke it), and had to locally and explicitly call it in their code. They had to be cognizant of what was going on. One could still identify which statements would execute in which order, and the pro- gram was still unitary: it exhibited a direct correspondence between one statement in the pro- gramming language written, one sequence of machine instructions executed. Inheritance in object-oriented programming (OOP) was the second important introduction of non-locality. Executing inherited behavior is non-local. There are two different fashions of inher- iting behavior, send super and mixins. Send-super systems like Java and Smalltalk allow the programmer to explicitly invoke the be- _,,_avior of its parent class or classes, without knowing exactly what behavior is being invoked. Adding behavior to classes higher in the class structure allows a limited form of quantified pro- gram statements--that is, statements that have effect on many loci in the underlying code. For example, suppose we wish to introduce a "display" aspect to a program about simulating traffic movement. We will want to make quantified statements like "Whenever something moves (exe- cutes its move method), the screen must be updated." Imagine that all things that move are de- scendants of the class of moveable-object. We can accomplish this with send-super inheritance, if we have a cooperative base-class programmer--that is, one who will consistently follow direc- tions. We make the behavior of the move method in movable-object be the display update and request the programmers of derivative classes to invoke send-super at the end of their code. This requires the derived class programmers to know that they have to do something, but relieves them of having to know what exactly it is that they have to do. We're also restricted with respect to the locus of behavior--we can ask programmers to do the send-super at the start of their code, or at the end, but our directions probably need to be consistent throughout the system. Requiring cooperation is not good enough. Programmers may fail to be systematically coop- erative, the base program may itself be already written or it may be otherwise out of our control. For true AOP, we want our system to work with oblivious programmers---ones who don't have to expend any additional effort to make the AOP mechanism work. The earliest example of oblivi- ous quantification is mixin inheritance, found in MacLisp and Symbolics Lisp [5,15]. With mix- ins, the derived-class functionality is determined by assembling the code of the derived class with the advice of its super classes. The aspect programmer can make quantified statements about the code by adding mixins, while the derived class programmer remains ignorant of these actions. The scope of quantification is controlled by which classes inherit the mixin. That is, we can quan- tify over the descendants of some superclass, for a given single method. In the screen update ex- ample, adding an "after" mixin to movable-object's move accomplishes the automatic update. In using inheritance to achieve aspects, single superclass inheritance systems require all as- pects to match the class structure of the original program, while multiple inheritance systems al- low quantification independent of the program's dominant decomposition. Mixins with multiple inheritance are thus a full aspect-oriented programming technology. In general, AOP can be understood as the desire to make quantified statements about the behavior of programs, and to have these quantifications hold over programs written by oblivious programmers. We want to be able to say, "This code realizes this concern. Execute it whenever these circum- stances hold." This breaks completely with local and unitary demands--we cart organize our pro- gram in the form most appropriate for coding and maintenance. We do not even need the local markings of cooperation. The weaving mechanism of the AOP system can, by itselt, take our quantified statements and the base program and produce the primitive directions to be performed. 3. Quantification AOP is thus the desire to make programming statements of the form In programs P, whenever condition C arises, perform action A. ( I) over "conventionally" coded programs P. This implies three major dimensions of concern for the designer and implementer of an AOP system: • Quantification: What kinds of'conditions C can we specify. • Interface: What is the interface of the actions A. That is, how do they interact with base programs and each other. =',", = Weaving: How will the system arrange to intermix the execution of the base actions of program P with the actions A. In an AOP system, we make quantified statements about which code is to execute in which cir- cumstances. Over what can we quantify? Broadly, we can quantify over the static structure of the system and over its dynamic behavior. 3.1. Static quantification The static structure is the program as text. Two common views of program text are in terms of the public interfaces of the program (typically methods, but occasionally also public variables) and as a parsed-program as abstract syntax tree. Black-box AOP systems quantify over the public interface of components like functions and object methods. Examples of black-box systems include Composition-Filters [2], synchronization advice [11] and OIF [8]. A simple implementation mechanism for black-box AOP is to wrap components with the aspect behavior. 3 Clear-box AOP systems allow quantification over the parsed structure of components. Exam- ples of such system include Aspect.I, which allows (among other things) quantifying over both the calling and
Details
-
File Typepdf
-
Upload Time-
-
Content LanguagesEnglish
-
Upload UserAnonymous/Not logged-in
-
File Pages7 Page
-
File Size-