440 likes | 562 Views
SE 510 Principles and Applications of Software Design. Aspect Oriented Programming October 5, 2005 Jeff Webb. Aspect-Oriented Programming. Gregor Kiczales, John Lamping, Anurag Mendhekar, Chris Maeda, Cristina Lopes, Jean-Marc Loingtier and John Irwin 1997 Xerox Palo Alto Research Center.
E N D
SE 510Principles and Applications of Software Design Aspect Oriented Programming October 5, 2005 Jeff Webb
Aspect-Oriented Programming Gregor Kiczales, John Lamping, Anurag Mendhekar, Chris Maeda, Cristina Lopes, Jean-Marc Loingtier and John Irwin 1997 Xerox Palo Alto Research Center
Background Information • The process of functional decomposition breaks a system down into smaller and smaller parts. • Units of behavior or function. • Programming languages provide mechanisms that allow us to define abstractions for these small parts and then compose them into systems.
Generalized Procedure Based Languages • Procedural • OO • Functional
“It feels comfortable to talk about what is encapsulated as a functional unit of the overall system”. ……………………….. • We will be considering units of decomposition that are not functional.
The Problem • There are many programming problems for which neither procedural nor object-oriented techniques are sufficient to clearly capture some of the important design decisions the program must implement. • Examples • Error detection and handling • Security issues • Logging
Without AOP • The implementation of those design decisions will be scattered throughout the code, resulting in “tangled code”.
The Problem • AOP’s core idea is “separating the business logic in an application from the common services that support it.”
The issues that make these design decisions so hard to clearly capture in code are called ASPECTS • The problem is that they CROSS-CUT the systems basic functionality.
Example • LISP • Image processing functions • Some primitive functions are developed and some compound functions • Requirements • Easy to develop and maintain • Efficient use of memory
A primitive image function “or!” Public Image or! (Image a, Image b){ Image result = new Image(); For i from 1 to width do{ For j from 1 to height do{ set-pixel (result i j) = or ((get-pixel a i j) (get-pixel b i j)); } } Return result; }
More functions Functionality Implementation • pixelwise logical operations written using loop primitive as or!, and!, not! above. • shift image up, down written using loop primitives; slightly different loop structure. • difference of two images Function remove! (a b) and!( a (not! b)) • pixels @ top edge of a region Function top-edge! (a) remove!(a (down! a)) • pixels @ bottom edge of a region Function bottom-edge! (a) remove!( a (up! a))
Easy to develop and maintain • High level function to return horizontal edge pixels Function horizontal-edge! (a){ Return or! (top-edge!(a) bottom-edge!(a)); }
Not memory efficient • Each procedure loops over a number of images • Many output images are created frequently, only to be quickly consumed by another loop • Results in excessively frequent memory references and storage allocation • Leads to cache misses, page faults and terrible performance
Solution to this problem • Take a more global approach and hand code the entire process into one, efficient piece of code.
Memory efficient Public Image horizontal-edge! (a){ Image result, a-up, a-down = new Image(); a-up = up!(a); a-down = down!(a); For i from 1 to width do{ For j from 1 to height do{ set-pixel(result i j) = or (and( (get-pixel a i j) (not (get-pixel a-up i j))) and (get-pixel a i j) (not (get-pixel a-down i j)) ) } // j for } // i for Return result; }
Problems • Tangled code • Difficult to maintain • Destroyed the original clear functional structure
Data Flow Diagram or! and! and! not! not! up! up! a
Memory efficient Public Image horizontal-edge! (a){ Image result, a-up, a-down = new Image(); a-up = up!(a); a-down = down!(a); For i from 1 to width do{ For j from 1 to height do{ set-pixel(result i j) = or (and( (get-pixel a i j) (not (get-pixel a-up i j))) and (get-pixel a i j) (not (get-pixel a-down i j)) ) } // j for } // i for Return result; }
Crux of the problem • Two properties are being implemented • 1 Functionality • 2 Loop fusion ( for the sake of memory ) • Both properties originate from primitive filters • They must compose differently as filters are composed
Cross-Cutting • Functionality composes hierarchically in the traditional way • Loop fusion composes by fusing the loops of those primitive filters that : • have the same loop structure • end up in a producer/consumer relationship at runtime • The properties cross-cut one another • This cross-cutting phenomena results in the tangled code
Problem with GP languages • Only provide one composition mechanism • Programmer must do the co-composition manually • Leads to complexity and tangling Solution • Use two different languages, One for the components and one for the aspects.
Component • Can be cleanly encapsulated in a generalized procedure (i.e. object, method, procedure, API) • By cleanly, we mean well-localized, and easily accessed and composed as necessary.
Aspect • Can not be cleanly encapsulated in a generalized procedure. • Aspects tend not to be units of the system’s functional decomposition, but rather to be properties that affect the performance or semantics of the components in systemic ways. • Examples of aspects include memory access patterns and synchronization of concurrent objects.
Goal of AOP • To support the programmer in cleanly separating components and aspects from each other, by providing mechanisms that make it possible to abstract and compose them to produce the overall system.
Programming with Aspects • Rewrite the components so they can be read by the weaver • Create an aspect program • Weave the two together to produce optimal intermediate code
Component Re-write Public iterater Image pixelwise(Image a, Image b, operator MyOp){ Image result = new Image(); For i from 1 to width do{ For j from 1 to height do{ set-pixel (result i j) = MyOp ((get-pixel a i j) (get-pixel b i j)); } } Return result; } Function or! (a a){ pixelwise( a b “or”) }
Component weaving • Weaver reads the component program and builds a data graph, noting the nodes and edges or! and! and! not! not!
Aspect Language program cond { if (loop-shape(currentNode) == ’pointwise’ and loop-shape(nextNode) == ’pointwise’){ fuse (currentNode, nextNode, ’pointwise’); } // end if } // end cond Where pointwise is an iterator function that takes 2 image parameters and an operator paramater.
Aspect weaving • Checks whether two nodes, that are connected by a data flow edge, both have a similar loop structure, • and if so it fuses them into a single loop that also has the particular structure, • and that has the appropriate merging of the inputs, loop variables and body of the two original loops.
Weaving output • Produces an optimally structured C program • Note that the real system required about a dozen or so aspects. • Program analysis and understanding are to significant for a compiler to be able to use
Results • Hand coding the basic functionality of original program required 768 loc (LISP) • The hand coded, optimized version implements • Fusion optimization • Memoization of intermediate results • Compile time memory allocation • Specialized intermediate data structures • 35213 loc • The tangled code is extremely difficult to maintain, since small changes to the functionality require mentally untangling and then re-tangling it.
Results • Base implementation and three aspect programs = 1039 loc • Time efficiency was comparable to hand coded version • Space efficiency was better than hand coded version.
References • Gregor Kiczales, John Lamping, Anurag Mendhekar, Chris Maeda, Cristina Lopes, Jean-Marc Loingtier and John Irwin. Aspect Oriented Programming, Proceedings of the ECOOP, Volume #32, issue 1ess, March 1997, pages 220-242 • http://jroller.com/page/colyer/20040531 • http://www.builderau.com.au/architect/0,39024564,39183763,00.htm • Memoization: http://dictionary.reference.com/search?q=memo%20function
Additional Example Person Owns Dog Taken from : http://jroller.com/page/colyer/20040531
Person Owns Dog • class Person • attribute numOfDogsOwned • simple accessor method getNumDogsOwned() Person numOfDogsOwned GetNumDogsOwned()
Person Owns Dog /** * not a dog in sight... */ public class Person { private String lastName; private Address address; ... public String getLastName() { return lastName; } ... }
Person Owns Dog /** * not a person in sight... */ public aspect DogOwnership { public interface IDogOwner {}; private int IDogOwner.numDogsOwned; public int IDogOwner.getNumDogsOwned() { return numDogsOwned; } }
Person Owns Dog - We want to create a dog-owning person • We could do this by creating a DogOwningPerson class • However dog-owning isn't limited to people • maybe an Organization can own dogs too?
Keep the concept of dog ownership independent of any one kind of dog owner public aspect PersonOwnsDog { declare parents : Person implements DogOwnership.IDogOwner; } - Now, Person and DogOwnership are independently reusable
Now you can call the getNumDogsOwned method on a Person Person person = new Person(); person.getNumDogsOwned();