@TECHREPORT{po-vis:ahmed-karl,
AUTHOR = "Ahmed Abdelmeged and Karl Lieberherr",
TITLE = "{Recursive Adaptive Computations Using Perobject Variables}",
YEAR = "2007",
INSTITUTION = "Northeastern University, Boston",
MONTH = "May",
NUMBER = "NU-CCIS-07-??
}
Notes by Karl:
This is a modularized version of the code in the TR. We start with the tangled code from the paper and then modularize it using inheritance. Instead of using inheritance we plan to use a DSL for PO visitor composition.
public class CheckerVisitor extends Visitor {
int totalViolations = 0;
@PerObject {
className = "Container"; initializer = "0"
} int myWeight;
public void before(Element e){
myWeight += e.weight;}
public void after(Container c){
myWeight += c.myWeight;
boolean vio =
c.capacity < c.myWeight;
if(vio){ totalViolations++; }
}
}
Concerns:
weight summation
WeightVisitor
violation predicate
VioVisitor
conditional update
Updater
CounterAcc
ListAcc
public class WeightVisitor extends Visitor {
int totalViolations = 0;
@PerObject {
className = "Container"; initializer = "0"
} int myWeight;
public void before(Element e){
myWeight += e.weight;}
public void after(Container c){
myWeight += c.myWeight; }
}
public class VioVisitor extends WeightVisitor {
@PerObject {
className = "Container"
} boolean vio;
public void after(Container c){
super.after(c);
c.vio = c.capacity < c.myWeight;
}
}
public class Updater extends VioVisitor {
public void after(Container c){
super.after(c);
if(c.vio){ update(c); }
}
void update(Container c) {};
}
public class CounterAcc
extends Updater {
int totalViolations = 0;
void update(Container c) {
totalViolations++; }
}
public class ListAcc extends Updater {
List violations = new List();
void update(Container c) {
violations = new Cons(c,violations); }
}
The current TR might give the wrong impression that PO visitors are only useful for recursive computations. They are also useful on non-recursive structures whenever we need easy access to objects "higher" up in the object.. They are a simplified version of transportation patterns described in chapter 10 of my book. Consider the perobject version of the CNF formula reduction problem: Formula = clauses: List(Clause) perobject sats: int perobject unsats: int perobject newClauses: List(Clause). Clause = literals: List(Literal) perobject newLiterals: List(Literal). Literal : Pos | Neg common Variable. Pos = . Neg = . Variable = v: int. void after (Literal l2) { reduce(l1,l2);} reduce(l1, l2) reduce(Pos(v), Pos(v)) = true: sats++ reduce(Neg(v), Neg(v)) = true: sats++ reduce(Neg(v), Pos(v)) = false: skip l2 reduce(Pos(v), Neg(v)) = false: skip l2 reduce(l1, l2) = l2 if l1 and l2 do not refer to the same variable: add l2 to newLiterals void after (Clause clause) if newLiterals is empty: unsats++ else add clause to newClauses;
Visitors influence traversals. Aspects influence Java programs. PO (perobject) variables are a part of visitors. Does it make sense to have perobject variables for aspects?
PO variables for aspects are also attached to a class. They are visible in the entire cflow of a suitable pointcut. Has this been proposed on the AspectJ mailing list?
There are several opportunities for optimization based on an analysis of how the visitors use the the per-object variable.
One of the benefits of attribute grammars is that they can transport information from anywhere in the abstract syntax tree to anywhere else, in a controlled and formal way. PO visitors share the same property but they not only transport, they also update the information automatically as part of a traversal.
A useful equation: Attribute Grammar = Parsing + AP + a universal traversal + simple PO visitors. The simple visitors update the inherited and synthesized attributes.