Aspect Oriented Programming

77
Aspect Oriented Programming An Overview of AspectJ

description

Aspect Oriented Programming. An Overview of AspectJ. What is AOP?. Not strictly OOP Not strictly POP Captures “aspects” that “crosscut” both More on this later. A simple image filter (v1). Other logical operations similar Shift image up, down similar. (defun or! (a b) - PowerPoint PPT Presentation

Transcript of Aspect Oriented Programming

Page 1: Aspect Oriented Programming

Aspect Oriented Programming

An Overview of AspectJ

Page 2: Aspect Oriented Programming

What is AOP?

• Not strictly OOP• Not strictly POP• Captures “aspects” that “crosscut”

both – More on this later

Page 3: Aspect Oriented Programming

(defun or! (a b) (let ((result (new-image))) (loop for i from 1 to width do (loop for j from 1 to height do (set-pixel result i j (or (get-pixel a i j) (get-pixel b i j))))) result))

A simple image filter (v1)

• Other logical operations similar• Shift image up, down similar

Page 4: Aspect Oriented Programming

A simple image filter (v2)

• Easy to understand, but not efficient

(defun top-edge! (a) (remove! a (down! a)))

(defun remove! (a b) (and! a (not! b)))

(defun bottom-edge! (a) (remove! a (up! a)))

(defun horizontal-edge! (a) (or! (top-edge! a) (bottom-edge! a)))

Difference of two images

Pixels at top edge of region

Pixels at bottom edge of region

Horizontal edge pixels

Page 5: Aspect Oriented Programming

A simple image filter (v2)

• Fewer image copies• Reasoning less obvious

(defun horizontal-edge-improved! (a) (let ((result (new-image)) (a-up (up! a)) (a-down (down! a))) (loop for i from 1 to width do (loop 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))))))) result))

Page 6: Aspect Oriented Programming

A simple image filter (v2)

Page 7: Aspect Oriented Programming

Lessons learned

• Efficiency is good!• Understanding is good!• Can’t we have both?

Page 8: Aspect Oriented Programming

good modularity

• XML parsing in org.apache.tomcat– red shows relevant lines of code– nicely fits in one box

XML parsing

Page 9: Aspect Oriented Programming

good modularity

• URL pattern matching in org.apache.tomcat– red shows relevant lines of code– nicely fits in two boxes (using inheritance)

URL pattern matching

Page 10: Aspect Oriented Programming

problems like…

• logging in org.apache.tomcat– red shows lines of code that handle logging – not in just one place– not even in a small number of places

logging is not modularized

Page 11: Aspect Oriented Programming

AspectJ

• Aspect Oriented environment for Java• Developed at Xerox PARC

Page 12: Aspect Oriented Programming

a simple figure editor

operations that move elements

factory methodsDisplay

*

2Point

getX()getY()setX(int)setY(int)move(int, int)

Line

getP1()getP2()setP1(Point)setP2(Point)move(int, int)

Figure

makePoint(..)makeLine(..)

FigureElement

move(int, int)

Page 13: Aspect Oriented Programming

a simple figure editor

class Line implements FigureElement{ private Point p1, p2; Point getP1() { return p1; } Point getP2() { return p2; } void setP1(Point p1) { this.p1 = p1; } void setP2(Point p2) { this.p2 = p2; } void moveBy(int dx, int dy) { ... }}

class Point implements FigureElement { private int x = 0, y = 0; int getX() { return x; } int getY() { return y; } void setX(int x) { this.x = x; } void setY(int y) { this.y = y; } void moveBy(int dx, int dy) { ... }}

Page 14: Aspect Oriented Programming

a Line

a Point

join points

returning or throwing

dispatch

dispatch

key points in dynamic call graph

a method callreturning or throwinga method execution

returning or throwinga method execution

imagine l.move(2, 2)

Page 15: Aspect Oriented Programming

join point terminology

• several kinds of join points– method & constructor call– method & constructor execution– field get & set– exception handler execution– static & dynamic initialization

a Line

dispatch

method call join points

method execution join points

Page 16: Aspect Oriented Programming

call(void Line.setP1(Point))

primitive pointcuts

a pointcut is a kind of predicate on join points that:– can match or not match any given join point and– optionally, can pull out some of the values at that join point

“a means of identifying join points”

matches if the join point is a method call with this signature

Page 17: Aspect Oriented Programming

pointcut composition

whenever a Line receives a “void setP1(Point)” or “void setP2(Point)” method call

or

a “void Line.setP2(Point)” call

a “void Line.setP1(Point)” call

call(void Line.setP1(Point)) || call(void Line.setP2(Point));

pointcuts compose like predicates, using &&, || and !

Page 18: Aspect Oriented Programming

user-defined pointcuts

user-defined (aka named) pointcuts– can be used in the same way as primitive pointcuts

defined using the pointcut construct

pointcut move(): call(void Line.setP1(Point)) || call(void Line.setP2(Point));

Page 19: Aspect Oriented Programming

pointcut move(): call(void Line.setP1(Point)) || call(void Line.setP2(Point));

after() returning: move() { <code here runs after each move> }

after advice action to take aftercomputation under join points

a Line

after advice runs“on the way back out”

Page 20: Aspect Oriented Programming

a simple aspect

an aspect defines a special class that can crosscut other classes

DisplayUpdating v1

box means complete running code

aspect DisplayUpdating {

pointcut move(): call(void Line.setP1(Point)) || call(void Line.setP2(Point));

after() returning: move() { Display.update(); }}

Page 21: Aspect Oriented Programming

without AspectJ

• what you would expect– update calls are tangled through the code– “what is going on” is less explicit

class Line { private Point p1, p2;

Point getP1() { return p1; } Point getP2() { return p2; }

void setP1(Point p1) { this.p1 = p1; Display.update(); } void setP2(Point p2) { this.p2 = p2; Display.update(); }}

DisplayUpdating v1

Page 22: Aspect Oriented Programming

pointcutscan cut across multiple classes

pointcut move(): call(void Line.setP1(Point)) || call(void Line.setP2(Point)) || call(void Point.setX(int)) || call(void Point.setY(int));

Page 23: Aspect Oriented Programming

pointcuts can use interface signatures

pointcut move(): call(void FigureElement.moveBy(int, int)) || call(void Line.setP1(Point)) || call(void Line.setP2(Point)) || call(void Point.setX(int)) || call(void Point.setY(int));

Page 24: Aspect Oriented Programming

a multi-class aspectDisplayUpdating v2

aspect DisplayUpdating {

pointcut move(): call(void FigureElement.moveBy(int, int)) || call(void Line.setP1(Point)) || call(void Line.setP2(Point)) || call(void Point.setX(int)) || call(void Point.setY(int));

after() returning: move() { Display.update(); }}

Page 25: Aspect Oriented Programming

pointcut move(FigureElement figElt): target(figElt) && (call(void FigureElement.moveBy(int, int)) || call(void Line.setP1(Point)) || call(void Line.setP2(Point)) || call(void Point.setX(int)) || call(void Point.setY(int)));

after(FigureElement fe) returning: move(fe) { <fe is bound to the figure element> }

using values at join points

• pointcut can explicitly expose certain values• advice can use value

demonstrate first, explain in detail afterwards

parameter mechanism being used

Page 26: Aspect Oriented Programming

explaining parameters…

• variable is bound by user-defined pointcut declaration– pointcut supplies value for variable– value is available to all users of user-defined pointcut

pointcut parameters pointcut move(Line l): target(l) && (call(void Line.setP1(Point)) || call(void Line.setP2(Point)));

after(Line line): move(line) { <line is bound to the line> }

typed variable in place of type name

of user-defined pointcut designator

Page 27: Aspect Oriented Programming

explaining parameters…

• variable is bound by advice declaration– pointcut supplies value for variable– value is available in advice body

pointcut move(Line l): target(l) && (call(void Line.setP1(Point)) || call(void Line.setP2(Point)));

after(Line line): move(line) { <line is bound to the line> }

typed variable in placeof type nameadvice parameters

of advice

Page 28: Aspect Oriented Programming

context & multiple classesDisplayUpdating v3

aspect DisplayUpdating {

pointcut move(FigureElement figElt): target(figElt) && (call(void FigureElement.moveBy(int, int)) || call(void Line.setP1(Point)) || call(void Line.setP2(Point)) || call(void Point.setX(int)) || call(void Point.setY(int)));

after(FigureElement fe): move(fe) { Display.update(fe); }}

Page 29: Aspect Oriented Programming

without AspectJ

class Line { private Point p1, p2;

Point getP1() { return p1; } Point getP2() { return p2; }

void setP1(Point p1) { this.p1 = p1;

} void setP2(Point p2) { this.p2 = p2;

}}

class Point { private int x = 0, y = 0;

int getX() { return x; } int getY() { return y; }

void setX(int x) { this.x = x;

} void setY(int y) { this.y = y;

}}

Page 30: Aspect Oriented Programming

class Line { private Point p1, p2;

Point getP1() { return p1; } Point getP2() { return p2; }

void setP1(Point p1) { this.p1 = p1; Display.update(); } void setP2(Point p2) { this.p2 = p2; Display.update(); }}

class Point { private int x = 0, y = 0;

int getX() { return x; } int getY() { return y; }

void setX(int x) { this.x = x;

} void setY(int y) { this.y = y;

}}

without AspectJDisplayUpdating v1

Page 31: Aspect Oriented Programming

class Line { private Point p1, p2;

Point getP1() { return p1; } Point getP2() { return p2; }

void setP1(Point p1) { this.p1 = p1; Display.update(); } void setP2(Point p2) { this.p2 = p2; Display.update(); }}

class Point { private int x = 0, y = 0;

int getX() { return x; } int getY() { return y; }

void setX(int x) { this.x = x; Display.update(); } void setY(int y) { this.y = y; Display.update(); }}

without AspectJDisplayUpdating v2

Page 32: Aspect Oriented Programming

class Line { private Point p1, p2;

Point getP1() { return p1; } Point getP2() { return p2; }

void setP1(Point p1) { this.p1 = p1; Display.update(this); } void setP2(Point p2) { this.p2 = p2; Display.update(this); }}

class Point { private int x = 0, y = 0;

int getX() { return x; } int getY() { return y; }

void setX(int x) { this.x = x; Display.update(this); } void setY(int y) { this.y = y; Display.update(this); }}

without AspectJ

• no locus of “display updating”– evolution is cumbersome– changes in all classes– have to track & change all callers

DisplayUpdating v3

Page 33: Aspect Oriented Programming

with AspectJ

class Line { private Point p1, p2;

Point getP1() { return p1; } Point getP2() { return p2; }

void setP1(Point p1) { this.p1 = p1; } void setP2(Point p2) { this.p2 = p2; }}

class Point { private int x = 0, y = 0;

int getX() { return x; } int getY() { return y; }

void setX(int x) { this.x = x; } void setY(int y) { this.y = y; }}

Page 34: Aspect Oriented Programming

with AspectJ

aspect DisplayUpdating { pointcut move(): call(void Line.setP1(Point)) || call(void Line.setP2(Point));

after() returning: move() { Display.update(); }}

DisplayUpdating v1

class Line { private Point p1, p2;

Point getP1() { return p1; } Point getP2() { return p2; }

void setP1(Point p1) { this.p1 = p1; } void setP2(Point p2) { this.p2 = p2; }}

class Point { private int x = 0, y = 0;

int getX() { return x; } int getY() { return y; }

void setX(int x) { this.x = x; } void setY(int y) { this.y = y; }}

Page 35: Aspect Oriented Programming

with AspectJDisplayUpdating v2

aspect DisplayUpdating { pointcut move(): call(void FigureElement.moveBy(int, int) || call(void Line.setP1(Point)) || call(void Line.setP2(Point)) || call(void Point.setX(int)) || call(void Point.setY(int));

after() returning: move() { Display.update(); }}

class Line { private Point p1, p2;

Point getP1() { return p1; } Point getP2() { return p2; }

void setP1(Point p1) { this.p1 = p1; } void setP2(Point p2) { this.p2 = p2; }}

class Point { private int x = 0, y = 0;

int getX() { return x; } int getY() { return y; }

void setX(int x) { this.x = x; } void setY(int y) { this.y = y; }}

Page 36: Aspect Oriented Programming

• clear display updating module– all changes in single aspect– evolution is modular

aspect DisplayUpdating { pointcut move(FigureElement figElt): target(figElt) && (call(void FigureElement.moveBy(int, int) || call(void Line.setP1(Point)) || call(void Line.setP2(Point)) || call(void Point.setX(int)) || call(void Point.setY(int)));

after(FigureElement fe) returning: move(fe) { Display.Update(fe); }}

with AspectJDisplayUpdating v3

class Line { private Point p1, p2;

Point getP1() { return p1; } Point getP2() { return p2; }

void setP1(Point p1) { this.p1 = p1; } void setP2(Point p2) { this.p2 = p2; }}

class Point { private int x = 0, y = 0;

int getX() { return x; } int getY() { return y; }

void setX(int x) { this.x = x; } void setY(int y) { this.y = y; }}

Page 37: Aspect Oriented Programming

aspects crosscut classes

aspect modularity cuts across class modularity

DisplayUpdating

Display

*

2Point

getX()getY()setX(int)setY(int)moveBy(int, int)

Line

getP1()getP2()setP1(Point)setP2(Point)moveBy(int, int)

Figure

makePoint(..)makeLine(..)

FigureElement

moveBy(int, int)

Page 38: Aspect Oriented Programming

advice is

• before before proceeding at join point

• after returning a value to join point• after throwing a throwable to join point• after returning to join point either way

• around on arrival at join point gets explicit control over when&if program proceeds

additional action to take at join points

Page 39: Aspect Oriented Programming

contract checking

• pre-conditions– check whether parameter is valid

• post-conditions– check whether values were set

• condition enforcement– force parameters to be valid

simple example of before/after/around

Page 40: Aspect Oriented Programming

pre-conditionusing before advice

aspect PointBoundsPreCondition { before(int newX): call(void Point.setX(int)) && args(newX) { assert(newX >= MIN_X); assert(newX <= MAX_X); } before(int newY): call(void Point.setY(int)) && args(newY) { assert(newY >= MIN_Y); assert(newY <= MAX_Y); }

private void assert(boolean v) { if ( !v ) throw new RuntimeException(); }}

what follows the ‘:’ is always a pointcut – primitive or user-defined

Page 41: Aspect Oriented Programming

post-condition

aspect PointBoundsPostCondition {

after(Point p, int newX): call(void Point.setX(int)) && target(p) && args(newX) { assert(p.getX() == newX); }

after(Point p, int newY): call(void Point.setY(int)) && target(p) && args(newY) { assert(p.getY() == newY); }

private void assert(boolean v) { if ( !v ) throw new RuntimeException(); }}

using after advice

Page 42: Aspect Oriented Programming

condition enforcement

aspect PointBoundsEnforcement {

void around(Point p, int newX): call(void Point.setX(int)) && target(p) && args(newX) { proceed(p, clip(newX, MIN_X, MAX_X)); }

void around(Point p, int newY): call(void Point.setY(int)) && target(p) && args(newY) { proceed(p, clip(newY, MIN_Y, MAX_Y)); }

private int clip(int val, int min, int max) { return Math.max(min, Math.min(max, val)); }}

using around advice

Page 43: Aspect Oriented Programming

wildcarding in pointcuts

target(Point)target(graphics.geom.Point)target(graphics.geom.*) any type in graphics.geomtarget(graphics..*) any type in any sub-package

of graphics

call(void Point.setX(int))call(public * Point.*(..)) any public method on Pointcall(public * *(..)) any public method on any type

call(void Point.getX())call(void Point.getY())call(void Point.get*())call(void get*()) any getter

call(Point.new(int, int))call(new(..)) any constructor

“*” is wild card“..” is multi-part wild card

Page 44: Aspect Oriented Programming

role types and reusable

abstract aspect Observing { protected interface Subject { } protected interface Observer { } public void addObserver(Subject s, Observer o) { ... } public void removeObserver(Subject s, Observer o) { ... }

abstract pointcut changes(Subject s);

after(Subject s): changes(s) { Iterator iter = getObservers(s).iterator(); while ( iter.hasNext() ) { notifyObserver(s, ((Observer)iter.next())); } } abstract void notifyObserver(Subject s, Observer o);}

Page 45: Aspect Oriented Programming

this is the concrete reuse

aspect DisplayUpdating extends Observing {

declare parents: FigureElement implements Subject; declare parents: Display implements Observer;

pointcut changes(Subject s): call(void FigureElement.moveBy(int, int)) || call(void Line.setP1(Point)) || call(void Line.setP2(Point)) || call(void Point.setX(int)) || call(void Point.setY(int));

void notifyObserver(Subject s, Observer o) { ((Display)o).needsRepaint(); }}

DisplayUpdating v4

Page 46: Aspect Oriented Programming

other primitive pointcuts

cflow(pointcut designator)all join points within the dynamic control flow of any join point in pointcut designator

cflowbelow(pointcut designator)all join points within the dynamic control flow below any join point in pointcut designator

Page 47: Aspect Oriented Programming

example 3

interface OutputStream { public void write(byte b); public void write(byte[] b);}

/** * This SIMPLE aspect keeps a global count of all * the bytes ever written to an OutputStream. */aspect ByteCounting {

int count = 0; int getCount() { return count; }

// // // what goes here? // // //}

counting bytes

Page 48: Aspect Oriented Programming

counting bytes v1

aspect ByteCounting {

int count = 0; int getCount() { return count; }

after() returning: call(void OutputStream.write(byte)) {

count = count + 1; }

after(byte[] bytes) returning: call(void OutputStream.write(bytes)) {

count = count + bytes.length; }}

a first attempt

Page 49: Aspect Oriented Programming

counting bytes

class SimpleOutputStream implements OutputStream { public void write(byte b) { … } public void write(byte[] b) {

for (int i = 0; i < b.length; i++) write(b[i]); }}

class OneOutputStream implements OutputStream { public void write(byte b) { … } public void write(byte[] b) { … }}

some stream implementations

Page 50: Aspect Oriented Programming

counting bytes

class OtherOutputStream implements OutputStream { public void write(byte b) {

byte[] bs = new byte[1] { b };write(bs);

} public void write(byte[] b) { … }}

another implementation

Page 51: Aspect Oriented Programming

counting bytes v2

aspect ByteCounting {

int count = 0; int getCount() { return count; } pointcut write(): call(void OutputStream.write(byte)) || call(void OutputStream.write(byte[]));

pointcut writeCflow(): cflowbelow(write());

after() returning: !writeCflow() && call(void OutputStream .write(byte)) {

count++; }

after(byte[] bytes) returning: !writeCflow() && call(void OutputStream .write(bytes)) {

count = count + bytes.length; }}

using cflowbelow for more robust counting

Page 52: Aspect Oriented Programming

AspectJ technology

• AspectJ is a small extension to Java™– valid Java programs are also valid AspectJ programs

• AspectJ has its own compiler, ajc– ajc runs on Java 2 platform (Java 1.2 – 1.4)– ajc produces Java platform compatible .class files

• AspectJ tools support– IDE extensions: Emacs, JBuilder 5, Forte4J– ajdoc to parallel javadoc – debugger: command line, GUI, & IDE

• license– compiler, runtime and tools are free for any use– compiler and tools are Open Source

Page 53: Aspect Oriented Programming

when are aspects appropriate?

• is there a concern that:– crosscuts the structure of several objects or operations– is beneficial to separate out

Page 54: Aspect Oriented Programming

… crosscutting

• a design concern that involves several objects or operations

• implemented without AOP would lead to distant places in the code that– do the same thing

• e.g. traceEntry(“Point.set”)• try grep to find these [Griswold]

– do a coordinated single thing• e.g. timing, observer pattern• harder to find these

Page 55: Aspect Oriented Programming

… beneficial to separate out

• does it improve the code in real ways?– separation of concerns

• e.g . think about service without timing– clarifies interactions, reduces tangling

• e.g. all the traceEntry are really the same– easier to modify / extend

• e.g. change the implementation of tracing• e.g. abstract aspect re-use

Page 56: Aspect Oriented Programming

Aspect Oriented Programming

Integrating Independent Components with On-Demand Remodularization

Page 57: Aspect Oriented Programming

interface TreeModel { Object getRoot(); Object[] getChildren(Object node); String getStringValue(Object node, boolean selected, boolean expanded, boolean leaf, int row, boolean focus); }}interface TreeGUIControl { display();}class SimpleTreeDisplay implements TreeGUIControl { TreeModel tm; display() { Object root = tm.getRoot(); ... tm.getChildren(root) ... ... tm.getStringValue(...); ... }}

A generic tree display

Page 58: Aspect Oriented Programming

class Expression { Expression[] subExpressions; String description() { ... } Expression[] getSubExpressions() { ... }}class ExpressionDisplay implements TreeModel { ExpressionDisplay(Expression r) { root = r; } Expression root; Object getRoot() { return root; } Object[] getChildren(Object node) { return ((Expression) node).getSubExpressions(); } String getStringValue(Object node, boolean selected, boolean expanded, boolean leaf, int row, boolean focus){ String s = ((Expression) node).description(); if (focus) s ="<"+s+">"; return s; }}

A generic tree display

Page 59: Aspect Oriented Programming

Problems with ExpressionDisplay

• Use of Object– What can we reason about structure,

dataflow?• Lose type safety

– Must rely on runtime checks

Page 60: Aspect Oriented Programming

class Expression { Expression[] subExpressions; String description() { ... } Expression[] getSubExpressions() { ... }}class ExpressionDisplay implements TreeModel { ExpressionDisplay(Expression r) { root = r; } Expression root; Object getRoot() { return root; } Object[] getChildren(Object node) { return ((Expression) node).getSubExpressions(); } String getStringValue(Object node, boolean selected, boolean expanded, boolean leaf, int row, boolean focus){ String s = ((Expression) node).description(); if (focus) s ="<"+s+">"; return s; }}

Problems with ExpressionDisplay

Page 61: Aspect Oriented Programming

Collaboration Interfaces

• Dual contracts– Provided: analogous to normal component

exports– Expected: “filled-in” by client for context

• Developer of component writes Provided parts– Assumes Expected parts to be filled in later

• Client must write Expected parts to complete component

Page 62: Aspect Oriented Programming

A generic tree display (CI)interface TreeDisplay { provided void display(); expected TreeNode getRoot();

interface TreeNode { expected TreeNode[] getChildren(); expected String getStringValue(); provided display(); provided boolean isSelected(), provided boolean isExpanded(); provided boolean isLeaf(); provided int row(); provided boolean hasFocus(); }}

Page 63: Aspect Oriented Programming

A generic tree display (CI)interface TreeDisplay { provided void display(); expected TreeNode getRoot();

interface TreeNode { expected TreeNode[] getChildren(); expected String getStringValue(); provided display(); provided boolean isSelected(), provided boolean isExpanded(); provided boolean isLeaf(); provided int row(); provided boolean hasFocus(); }} Implementer writes these

Page 64: Aspect Oriented Programming

A generic tree display (CI)interface TreeDisplay { provided void display(); expected TreeNode getRoot();

interface TreeNode { expected TreeNode[] getChildren(); expected String getStringValue(); provided display(); provided boolean isSelected(), provided boolean isExpanded(); provided boolean isLeaf(); provided int row(); provided boolean hasFocus(); }} Binder writes these

Page 65: Aspect Oriented Programming

Implementing the interfaceclass SimpleTreeDisplay implements TreeDisplay { void onSelectionChange(TreeNode n, boolean selected) { n.setSelected(true); } void display() { getRoot().display(); } class TreeNode { boolean selected; boolean isSelected() { return selected; } void setSelected(boolean s) { selected =s;} void display() { ... TreeNode c = getChildren()[i]; ... paint(position, c.getStringValue()); ... } }} Called, but not defined yet

Page 66: Aspect Oriented Programming

Binding the interfaceclass ExpressionDisplay binds TreeDisplay { Expression root; public ExpressionDisplay(Expression rootExpr) { root = rootExpr; } TreeNode getRoot() { return ExprTreeNode(root); } class ExprTreeNode binds TreeNode { Expression e; ExprTreeNode(Expression e) { this.e=e;} TreeNode[] getChildren() { return ExprTreeNode[](e.getSubExpressions()); } String getStringValue() { String s = e.description(); if (hasFocus()) s ="<"+s+">"; return s; } } }

Page 67: Aspect Oriented Programming

Instantiating the interface

• Neither class is sufficient by itself• Create “compound” class that

combines both• Compound class defined using “+”

class SimpleExpressionDisplay = SimpleTreeDisplay + ExpressionDisplay;...class Plus extends Expression { … }class Times extends Expression { … }Expression test = new Plus(new Times(5, 3), 9);TreeDisplay t = new SimpleExpressionDisplay(test);t.display();

Page 68: Aspect Oriented Programming

Wrapper recycling

• When returning nested objects, don’t use new– Avoid multiple “wrappers” for same object

• Wrapper provides 1-1 mapping to embedded object

• Uses map for lookups– 1st time, create new nested object– Subsequent wrappings of same embedded

object return same nested object

Page 69: Aspect Oriented Programming

Wrapper recyclingclass ExpressionDisplay binds TreeDisplay { Expression root; public ExpressionDisplay(Expression rootExpr) { root = rootExpr; } TreeNode getRoot() { return ExprTreeNode(root); } class ExprTreeNode binds TreeNode { Expression e; ExprTreeNode(Expression e) { this.e=e;} TreeNode[] getChildren() { return ExprTreeNode[](e.getSubExpressions()); } String getStringValue() { String s = e.description(); if (hasFocus()) s ="<"+s+">"; return s; } } }

Page 70: Aspect Oriented Programming

Type safety

• Virtual types– All nested interfaces, nested bindings, and

nested implementations are virtual– Virtual types defined by enclosing instance– Exposed nested objects are compound types

Page 71: Aspect Oriented Programming

Type safety

Expression e = ...;final ExpressionDisplay ed = new SimpleExpressionDisplay(e);...// let FileSystemDisplay be a binding of// TreeDisplay to the file system structureSimpleFileSystemDisplay = SimpleTreeDisplay + FileSystemDisplay;FileSystem fs = ... ;final FileSystemDisplay fsd = new SimpleFileSystemDisplay(fs);...ed.TreeNode t = ed.getRoot();fsd.setRoot(t); // Type error detected by typechecker!// fsd.TreeNode is not subtype of ed.TreeNode

Page 72: Aspect Oriented Programming

Type safety (polymorphism)

• We can still have polymorphism• If C = A + B, then

– C < A– C < B

Page 73: Aspect Oriented Programming

Type safety (polymorphism)class SucAugSched =

SuccessiveAugmentationColoring + SchedulingGraph;

class SimAnSched =

SimulatedAnnealingColoring + SchedulingGraph;

...

final SchedulingGraph sg =

wantSucAug ? new SucAugSched() : new SimAnSched();

sg.computeMinimumColoring( sg.CourseVertex[](courses) );

SucAugSched < SchedulingGraph and

SimAnSched < SchedulingGraph, so this is okay

Page 74: Aspect Oriented Programming

Type safety (polymorphism)

• Multiple bindings of nested classes allowed

• Only one implementation of nested classes

• Constructors defined at binding site only

• Asymmetry

Page 75: Aspect Oriented Programming

Type safety (polymorphism)class StudentKnowsTeacherGraph binds Graph { class StudVertex binds Vertex { final Student s; StudVertex(Student s) {this.s=s;} ... }

class TeacherVertex binds Vertex { Teacher t; TeacherVertex(Teacher t) { this.t = t; } ... }

... Vertex v1 = StudVertex(aStudent); ... ... Vertex v2 = TeacherVertex(aTeacher); ...}

Page 76: Aspect Oriented Programming

Conclusions

• Is this AOP?– In broad sense, maybe (not exactly OOP or

POP)– Not typical crosscutting

• Similar to Jiazzi– “mixins” done at finer grain (procedure level)

• Could we solve with templates (generics)?

Page 77: Aspect Oriented Programming

Conclusions

• Do we buy it?– Adds type safety – Wrapper recycling not terribly exciting