Towards Typesafe Join Points for Modular Reasoning in - - PowerPoint PPT Presentation

towards typesafe join points for modular reasoning in
SMART_READER_LITE
LIVE PREVIEW

Towards Typesafe Join Points for Modular Reasoning in - - PowerPoint PPT Presentation

Towards Typesafe Join Points for Modular Reasoning in Aspect-Oriented Programs Eric Bodden joint work with Milton Inostroza, ric Tanter


slide-1
SLIDE 1

Towards Typesafe Join Points for Modular Reasoning in Aspect-Oriented Programs

Eric Bodden joint work with Milton Inostroza, Éric Tanter

 





slide-2
SLIDE 2

Aspect-oriented programming successfully modularizes crosscutting concerns.

2

slide-3
SLIDE 3

Aspect-oriented programming successfully modularizes crosscutting concerns.

Aspect-oriented programming fails to preserve modular reasoning.

2

slide-4
SLIDE 4

AOP is ...

3

slide-5
SLIDE 5

AOP is ...

3

Programming support for implementing a separation of concerns

slide-6
SLIDE 6

Class C Aspect A

pointcut advice

Dependencies in traditional AOP

join point (shadow)

Global reasoning

4

Main-stream software developer AOP Expert

slide-7
SLIDE 7

Join Point Interfaces

5

slide-8
SLIDE 8

Class ¡C Aspect ¡A

advice

Join Point Interfaces (JPI)

join ¡point (shadow)

jpi

pointcut

exhibit

Separate evolution

6

Main-stream software developer AOP Expert

slide-9
SLIDE 9

jpi ¡ReturnType ¡Name ¡(FormalParameters)* ¡CheckedExceptions*

Fixed contract Separate evolution Modular reasoning

7

No weave time errors

“just like a method signature”

slide-10
SLIDE 10

8

Birthday discount in an online shopping system: 5% off for purchases

  • n your birthday
slide-11
SLIDE 11

Aspect code

jpi ¡void ¡CheckingOut(float ¡price, ¡Customer ¡c)

9

slide-12
SLIDE 12

Aspect code

jpi ¡void ¡CheckingOut(float ¡price, ¡Customer ¡c)

aspect ¡Discount{ void ¡around ¡CheckingOut(float ¡price, ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡Customer ¡cus){ int ¡factor ¡= ¡cus.hasBirthday() ¡? ¡0.95 ¡: ¡1; proceed(price*factor, ¡cus); } }

9

No reference to “base code” !

slide-13
SLIDE 13

Base code

class ¡ShoppingSession{ ShoppingCart ¡sc ¡= ¡new ¡ShoppingCart(); Invoice ¡inv ¡= ¡new ¡Invoice(); void ¡checkOut(Item ¡item, ¡float ¡price, ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡int ¡amount, ¡Customer ¡cust){ sc.add(item, ¡amount); inv.add(item, ¡amount, ¡cus); } }

10

No reference to Discount aspect !

jpi ¡void ¡CheckingOut(float ¡price, ¡Customer ¡c)

slide-14
SLIDE 14

class ¡ShoppingSession{ ... void ¡checkOut(Item ¡item, ¡float ¡price, ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡int ¡amount, ¡Customer ¡cus){ sc.add(item, ¡amount); inv.add(item, ¡amount, ¡cus); } exhibits ¡void ¡CheckingOut(float ¡price, ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡Customer ¡cus): call(* ¡checkOut(..)) && ¡args(*,price,*,cus); }

11

Base code

jpi ¡void ¡CheckingOut(Item ¡i, ¡float ¡price, ¡int ¡amt, ¡Customer ¡c)

slide-15
SLIDE 15

JPIs give you...

complete de-coupling of base and aspects therefore code can evolve independently no weave-time errors: language-semantics of Java preserved increases potential to re-use aspects

12

slide-16
SLIDE 16

13

Sometimes unable to define a pointcut at all...

slide-17
SLIDE 17

14

int monteCarloAlg() { long seed = System.currentTimeMillis(); System.out.println(“seed was:”+seed); int result = monteCarlo(seed); return result; }

slide-18
SLIDE 18

14

int monteCarloAlg() { long seed = System.currentTimeMillis(); System.out.println(“seed was:”+seed); int result = monteCarlo(seed); return result; } void around(long seed): monteCarloCall(seed) { proceed(0); }

slide-19
SLIDE 19

14

int monteCarloAlg() { long seed = System.currentTimeMillis(); System.out.println(“seed was:”+seed); int result = monteCarlo(seed); return result; } void around(long seed): monteCarloCall(seed) { proceed(0); } pointcut monteCarloCall(long seed):

slide-20
SLIDE 20

14

int monteCarloAlg() { long seed = System.currentTimeMillis(); System.out.println(“seed was:”+seed); int result = monteCarlo(seed); return result; } void around(long seed): monteCarloCall(seed) { proceed(0); } pointcut monteCarloCall(long seed): withincode(* monteCarloAlg())

slide-21
SLIDE 21

14

int monteCarloAlg() { long seed = System.currentTimeMillis(); System.out.println(“seed was:”+seed); int result = monteCarlo(seed); return result; } void around(long seed): monteCarloCall(seed) { proceed(0); } pointcut monteCarloCall(long seed): withincode(* monteCarloAlg()) && call(* monteCarlo(long)) && args(seed)

slide-22
SLIDE 22

14

int monteCarloAlg() { long seed = System.currentTimeMillis(); System.out.println(“seed was:”+seed); int result = monteCarlo(seed); return result; } void around(long seed): monteCarloCall(seed) { proceed(0); } pointcut monteCarloCall(long seed): withincode(* monteCarloAlg()) && call(* monteCarlo(long)) && args(seed) .. call(* println(..)) && args(???)

?

slide-23
SLIDE 23

Solution: Block Joinpoints!

slide-24
SLIDE 24

Solution: Block Joinpoints! Non-

slide-25
SLIDE 25

IIIA

16

Friedrich Steimann, Thomas Pawlitzki, Sven Apel, and Christian Kästner. Types and modularity for implicit invocation with implicit announcement. TOSEM, 20(1):1–43, 2010. int monteCarloAlg() { long seed = System.currentTimeMillis(); int result; exhibit SomeAspect.JP(seed) { System.out.println(“seed was:”+seed); result = monteCarlo(seed); } return result; } joinpointtype JP{ long theSeed; } void around(JP j) { }

slide-26
SLIDE 26

IIIA

16

Friedrich Steimann, Thomas Pawlitzki, Sven Apel, and Christian Kästner. Types and modularity for implicit invocation with implicit announcement. TOSEM, 20(1):1–43, 2010. int monteCarloAlg() { long seed = System.currentTimeMillis(); int result; exhibit SomeAspect.JP(seed) { System.out.println(“seed was:”+seed); result = monteCarlo(seed); } return result; } joinpointtype JP{ long theSeed; } void around(JP j) { } j.theSeed = 0; proceed(j);

slide-27
SLIDE 27

IIIA

16

Friedrich Steimann, Thomas Pawlitzki, Sven Apel, and Christian Kästner. Types and modularity for implicit invocation with implicit announcement. TOSEM, 20(1):1–43, 2010. int monteCarloAlg() { long seed = System.currentTimeMillis(); int result; exhibit SomeAspect.JP(seed) { System.out.println(“seed was:”+seed); result = monteCarlo(seed); } return result; } joinpointtype JP{ long theSeed; } void around(JP j) { } j.theSeed = 0; proceed(j);

?

slide-28
SLIDE 28

IIIA

16

Friedrich Steimann, Thomas Pawlitzki, Sven Apel, and Christian Kästner. Types and modularity for implicit invocation with implicit announcement. TOSEM, 20(1):1–43, 2010. int monteCarloAlg() { long seed = System.currentTimeMillis(); int result; exhibit SomeAspect.JP(seed) { System.out.println(“seed was:”+seed); result = monteCarlo(seed); } return result; } joinpointtype JP{ long theSeed; } void around(JP j) { } j.theSeed = 0; proceed(j); joinpointtype JP{ long seed; } void around(JP j) { j.seed = 0; proceed(j); }

seed==<time> seed==0 seed==<time>

slide-29
SLIDE 29

IIIA

16

Friedrich Steimann, Thomas Pawlitzki, Sven Apel, and Christian Kästner. Types and modularity for implicit invocation with implicit announcement. TOSEM, 20(1):1–43, 2010. int monteCarloAlg() { long seed = System.currentTimeMillis(); int result; exhibit SomeAspect.JP(seed) { System.out.println(“seed was:”+seed); result = monteCarlo(seed); } return result; } joinpointtype JP{ long theSeed; } void around(JP j) { } joinpointtype JP{ long seed; } void around(JP j) { j.seed = 0; proceed(j); } new Thread() { public void run() { proceed(j); } }.start();

result==???

slide-30
SLIDE 30

IIIA

16

Friedrich Steimann, Thomas Pawlitzki, Sven Apel, and Christian Kästner. Types and modularity for implicit invocation with implicit announcement. TOSEM, 20(1):1–43, 2010. int monteCarloAlg() { long seed = System.currentTimeMillis(); int result; exhibit SomeAspect.JP(seed) { System.out.println(“seed was:”+seed); result = monteCarlo(seed); } return result; } joinpointtype JP{ long theSeed; } void around(JP j) { } joinpointtype JP{ long seed; } void around(JP j) { j.seed = 0; proceed(j); } new Thread() { public void run() { proceed(j); } }.start();

result==???

slide-31
SLIDE 31

Key finding

17

slide-32
SLIDE 32

Key finding

17

code can be joinpoint code can be extracted into a method <=>

slide-33
SLIDE 33

Solution 1: Extract-method refactoring

slide-34
SLIDE 34

Solution 1: Extract-method refactoring Solution 2: Closure Joinpoints

slide-35
SLIDE 35

Closure Joinpoints

mark code with closures instead of blocks

  • more verbose than blocks
  • also more restrictive

but: very strong static guarantees

+ allows for modular type checking + calling a closure joinpoint can never fail + no data races on local variables

19

slide-36
SLIDE 36

20

int monteCarloAlg() { long seed = System.currentTimeMillis(); int result; result = exhibit JP(long theSeed) { System.out.println(“seed was:”+theSeed); return monteCarlo(theSeed); }(seed); return result; } jpi int JP(long s); int around JP (long mySeed) { }

slide-37
SLIDE 37

20

int monteCarloAlg() { long seed = System.currentTimeMillis(); int result; result = exhibit JP(long theSeed) { System.out.println(“seed was:”+theSeed); return monteCarlo(theSeed); }(seed); return result; } jpi int JP(long s); int around JP (long mySeed) { }

slide-38
SLIDE 38

20

int monteCarloAlg() { long seed = System.currentTimeMillis(); int result; result = exhibit JP(long theSeed) { System.out.println(“seed was:”+theSeed); return monteCarlo(theSeed); }(seed); return result; } jpi int JP(long s); int around JP (long mySeed) { }

slide-39
SLIDE 39

20

int monteCarloAlg() { long seed = System.currentTimeMillis(); int result; result = exhibit JP(long theSeed) { System.out.println(“seed was:”+theSeed); return monteCarlo(theSeed); }(seed); return result; } jpi int JP(long s); int around JP (long mySeed) { } return proceed(0);

slide-40
SLIDE 40

20

int monteCarloAlg() { long seed = System.currentTimeMillis(); int result; result = exhibit JP(long theSeed) { System.out.println(“seed was:”+theSeed); return monteCarlo(theSeed); }(seed); return result; } jpi int JP(long s); int around JP (long mySeed) { } return proceed(0);

slide-41
SLIDE 41

20

int monteCarloAlg() { long seed = System.currentTimeMillis(); int result; result = exhibit JP(long theSeed) { System.out.println(“seed was:”+theSeed); return monteCarlo(theSeed); }(seed); return result; } jpi int JP(long s); int around JP (long mySeed) { } return proceed(0);

slide-42
SLIDE 42

20

int monteCarloAlg() { long seed = System.currentTimeMillis(); int result; result = exhibit JP(long theSeed) { System.out.println(“seed was:”+theSeed); return monteCarlo(theSeed); }(seed); return result; } jpi int JP(long s); int around JP (long mySeed) { } return proceed(0);

slide-43
SLIDE 43

20

int monteCarloAlg() { long seed = System.currentTimeMillis(); int result; result = exhibit JP(long theSeed) { System.out.println(“seed was:”+theSeed); return monteCarlo(theSeed); }(seed); return result; } jpi int JP(long s); int around JP (long mySeed) { } return proceed(0);

seed==<time> theSeed==0

slide-44
SLIDE 44

20

int monteCarloAlg() { long seed = System.currentTimeMillis(); int result; result = exhibit JP(long theSeed) { System.out.println(“seed was:”+theSeed); return monteCarlo(theSeed); }(seed); return result; } jpi int JP(long s); int around JP (long mySeed) { } return proceed(0);

seed==<time> theSeed==0

slide-45
SLIDE 45

20

int monteCarloAlg() { long seed = System.currentTimeMillis(); int result; result = exhibit JP(long theSeed) { System.out.println(“seed was:”+theSeed); return monteCarlo(theSeed); }(seed); return result; } jpi int JP(long s); int around JP (long mySeed) { } return proceed(0);

seed==<time> theSeed==0

slide-46
SLIDE 46

20

int monteCarloAlg() { long seed = System.currentTimeMillis(); int result; result = exhibit JP(long theSeed) { System.out.println(“seed was:”+theSeed); return monteCarlo(theSeed); }(seed); return result; } jpi int JP(long s); int around JP (long mySeed) { } new Thread() { public void run() { proceed(mySeed); } }.start();

result==???

slide-47
SLIDE 47

20

int monteCarloAlg() { long seed = System.currentTimeMillis(); int result; result = exhibit JP(long theSeed) { System.out.println(“seed was:”+theSeed); return monteCarlo(theSeed); }(seed); return result; } jpi int JP(long s); int around JP (long mySeed) { } new Thread() { public void run() { proceed(mySeed); } }.start();

result==??? CJPs are expressions, not statements!

slide-48
SLIDE 48

20

int monteCarloAlg() { long seed = System.currentTimeMillis(); int result; result = exhibit JP(long theSeed) { System.out.println(“seed was:”+theSeed); return monteCarlo(theSeed); }(seed); return result; } jpi int JP(long s); int around JP (long mySeed) { } new Thread() { public void run() { proceed(mySeed); } }.start(); return 42;

result==42 CJPs are expressions, not statements!

slide-49
SLIDE 49

Closure joinpoints: aspect side

21

JPIs, as before

jpi int JP(long s); int around JP(long seed) { return proceed(0); }

advice directly refers to that joinpoint type no pointcuts required

slide-50
SLIDE 50

Closure joinpoints: base-code side

22

result = exhibit JP(long theSeed) { println(“seed was:”+theSeed); return monteCarlo(theSeed); }(seed);

base code exhibits joinpoint as call to closure reference to same JPI

jpi int JP(long s);

slide-51
SLIDE 51

Variable-access rules

23

class C { Field f; void foo(Param fp) { Local l; final Local L; exhibit JP(Param cp) { }(..); } }

slide-52
SLIDE 52

Variable-access rules

23

class C { Field f; void foo(Param fp) { Local l; final Local L; exhibit JP(Param cp) { }(..); } } f = null;

May read and write fields

slide-53
SLIDE 53

Variable-access rules

23

class C { Field f; void foo(Param fp) { Local l; final Local L; exhibit JP(Param cp) { }(..); } } println(cp);

May read (and write) closure parameters

slide-54
SLIDE 54

Variable-access rules

23

class C { Field f; void foo(Param fp) { Local l; final Local L; exhibit JP(Param cp) { }(..); } } println(L);

May read final locals

slide-55
SLIDE 55

Variable-access rules

23

class C { Field f; void foo(Param fp) { Local l; final Local L; exhibit JP(Param cp) { }(..); } }

May NOT access non-final locals

println(l); println(fp);

X X

slide-56
SLIDE 56

Control-flow rules

24

class C { void foo() { for(int i=0;i<5;i++) { exhibit JP(){ }(); println(i); } } }

slide-57
SLIDE 57

Control-flow rules

24

class C { void foo() { for(int i=0;i<5;i++) { exhibit JP(){ }(); println(i); } } } return;

slide-58
SLIDE 58

Control-flow rules

24

class C { void foo() { for(int i=0;i<5;i++) { exhibit JP(){ }(); println(i); } } } return; void around JP() { new Thread() { public void run() { proceed(); } }.start(); }

“upward FUNARG problem” (Weizenbaum 1968, Moses 1970)

slide-59
SLIDE 59

Control-flow rules

24

class C { void foo() { for(int i=0;i<5;i++) { exhibit JP(){ }(); println(i); } } } return;

break/continue/return always bind to closure, not to declaring method!

1 2 3 4 5

prints:

slide-60
SLIDE 60

Control-flow rules

24

class C { void foo() { for(int i=0;i<5;i++) { exhibit JP(){ }(); println(i); } } }

break/continue/return always bind to closure, not to declaring method!

break;

slide-61
SLIDE 61

Control-flow rules

24

class C { void foo() { for(int i=0;i<5;i++) { exhibit JP(){ }(); println(i); } } }

break/continue/return always bind to closure, not to declaring method!

continue;

slide-62
SLIDE 62

Syntactic sugar

25

exhibit JP(){ }(); exhibit JP{ };

slide-63
SLIDE 63

CJPs and JPIs

26

Tight integration: A closure joinpoint is just a special joinpoint and is processed like any

  • ther joinpoint.
slide-64
SLIDE 64
slide-65
SLIDE 65

Will it blend?

slide-66
SLIDE 66

Will it blend?

www.willitblend.com

slide-67
SLIDE 67

Will it blend?

t y p e ?

slide-68
SLIDE 68

Checked Exceptions

30

jpi void JPNone(); jpi void JPEx() throws Exception;

slide-69
SLIDE 69

Checked Exceptions

30

jpi void JPNone(); jpi void JPEx() throws Exception; before JPNone() throws Exception { } before JPEx() throws Exception { }

Will it type?

slide-70
SLIDE 70

Checked Exceptions

30

jpi void JPNone(); jpi void JPEx() throws Exception; before JPNone() throws Exception { } before JPEx() throws Exception { }

Will it type?

slide-71
SLIDE 71

Checked Exceptions

30

jpi void JPNone(); jpi void JPEx() throws Exception; before JPNone() throws Exception { } before JPEx() throws Exception { } void foo() { ... exhibit JPNone() { ... } } void bar() { ... exhibit JPEx() { ... } }

Will it type?

slide-72
SLIDE 72

Checked Exceptions

30

jpi void JPNone(); jpi void JPEx() throws Exception; before JPNone() throws Exception { } before JPEx() throws Exception { } void foo() { ... exhibit JPNone() { ... } } void bar() { ... exhibit JPEx() { ... } }

Will it type?

slide-73
SLIDE 73

Invariant Return Types

31

public aspect TestCase { static void correct() { HashSet s = exhibit JP { ... }; } jpi HashSet JP(); Set around JP() { return new TreeSet(); } }

slide-74
SLIDE 74

Invariant Return Types

31

public aspect TestCase { static void correct() { HashSet s = exhibit JP { ... }; } jpi HashSet JP(); Set around JP() { return new TreeSet(); } }

slide-75
SLIDE 75

Invariant Return Types

31

public aspect TestCase { static void correct() { HashSet s = exhibit JP { ... }; } jpi HashSet JP(); Set around JP() { return new TreeSet(); } }

slide-76
SLIDE 76

Invariant Return Types

31

public aspect TestCase { static void correct() { HashSet s = exhibit JP { ... }; } jpi HashSet JP(); Set around JP() { return new TreeSet(); } } HashSet around JP() {

slide-77
SLIDE 77

Invariant Return Types

31

public aspect TestCase { static void correct() { HashSet s = exhibit JP { ... }; } jpi HashSet JP(); Set around JP() { return new TreeSet(); } } HashSet around JP() {

... the same applies to argument types.

(Alternative: StrongAspectJ, De Fraine et al., AOSD 08)

slide-78
SLIDE 78

32

Invariant Pointcuts

jpi ¡void ¡JP(Number ¡n); aspect ¡A{ ¡ ¡exhibits ¡void ¡JP(Number ¡n) ¡: ¡call(void ¡*(..)) ¡&& ¡args(n); ¡ ¡public ¡static ¡void ¡main(String[] ¡args){ ¡ ¡ ¡ ¡ ¡ ¡foo(new ¡Integer(2)); ¡ ¡} ¡ ¡void ¡around ¡JP(Number ¡l){ ¡ ¡ ¡ ¡ ¡ ¡proceed(new ¡Float(3)); ¡ ¡} ¡ ¡public ¡static ¡void ¡foo(Integer ¡a){} }

slide-79
SLIDE 79

32

Invariant Pointcuts

jpi ¡void ¡JP(Number ¡n); aspect ¡A{ ¡ ¡exhibits ¡void ¡JP(Number ¡n) ¡: ¡call(void ¡*(..)) ¡&& ¡args(n); ¡ ¡public ¡static ¡void ¡main(String[] ¡args){ ¡ ¡ ¡ ¡ ¡ ¡foo(new ¡Integer(2)); ¡ ¡} ¡ ¡void ¡around ¡JP(Number ¡l){ ¡ ¡ ¡ ¡ ¡ ¡proceed(new ¡Float(3)); ¡ ¡} ¡ ¡public ¡static ¡void ¡foo(Integer ¡a){} }

AspectJ: match

slide-80
SLIDE 80

32

Invariant Pointcuts

jpi ¡void ¡JP(Number ¡n); aspect ¡A{ ¡ ¡exhibits ¡void ¡JP(Number ¡n) ¡: ¡call(void ¡*(..)) ¡&& ¡args(n); ¡ ¡public ¡static ¡void ¡main(String[] ¡args){ ¡ ¡ ¡ ¡ ¡ ¡foo(new ¡Integer(2)); ¡ ¡} ¡ ¡void ¡around ¡JP(Number ¡l){ ¡ ¡ ¡ ¡ ¡ ¡proceed(new ¡Float(3)); ¡ ¡} ¡ ¡public ¡static ¡void ¡foo(Integer ¡a){} } argsinv(n);

argsinv: no match

slide-81
SLIDE 81

33

Invariant Pointcuts

Same for thisinv and targetinv Warning if exhibits uses this/target/args Not nice but maybe AspectJ should have used different semantics in the first place...

slide-82
SLIDE 82

More flexible typing through type parameters

34

void printSet(Set s) { ... } Set around LogMe() { Set ret = proceed(); printSet(ret); return ret; } jpi Set LogMe(); exhibits Set LogMe(): call(* foo()); HashSet foo() { .. } HashSet s = foo();

slide-83
SLIDE 83

More flexible typing through type parameters

34

void printSet(Set s) { ... } Set around LogMe() { Set ret = proceed(); printSet(ret); return ret; } jpi Set LogMe(); exhibits Set LogMe(): call(* foo()); HashSet foo() { .. } HashSet s = foo(); new TreeSet();

slide-84
SLIDE 84

More flexible typing through type parameters

34

void printSet(Set s) { ... } Set around LogMe() { Set ret = proceed(); printSet(ret); return ret; } jpi Set LogMe(); exhibits Set LogMe(): call(* foo()); HashSet foo() { .. } HashSet s = foo(); new TreeSet();

slide-85
SLIDE 85

More flexible typing through type parameters

34

void printSet(Set s) { ... } Set around LogMe() { Set ret = proceed(); printSet(ret); return ret; } jpi Set LogMe(); exhibits Set LogMe(): call(* foo()); HashSet foo() { .. } HashSet s = foo(); new TreeSet();

Prevent error by not matching!

slide-86
SLIDE 86

void printSet(Set s) { ... } <S extends Set> S around LogMe() { S ret = proceed(); printSet(ret); return ret; }

More flexible typing through type parameters

35

jpi <S extends Set> S LogMe(); <S extends Set> exhibits S LogMe(): call(* foo()); HashSet foo() { .. } HashSet s = foo();

StrongAspectJ, De Fraine et al., AOSD 08

slide-87
SLIDE 87

void printSet(Set s) { ... } <S extends Set> S around LogMe() { S ret = proceed(); printSet(ret); return ret; }

More flexible typing through type parameters

35

jpi <S extends Set> S LogMe(); <S extends Set> exhibits S LogMe(): call(* foo()); HashSet foo() { .. } HashSet s = foo();

StrongAspectJ, De Fraine et al., AOSD 08

slide-88
SLIDE 88

void printSet(Set s) { ... } <S extends Set> S around LogMe() { S ret = proceed(); printSet(ret); return ret; }

More flexible typing through type parameters

35

jpi <S extends Set> S LogMe(); <S extends Set> exhibits S LogMe(): call(* foo()); HashSet foo() { .. } HashSet s = foo(); new TreeSet();

StrongAspectJ, De Fraine et al., AOSD 08

slide-89
SLIDE 89

void printSet(Set s) { ... } <S extends Set> S around LogMe() { S ret = proceed(); printSet(ret); return ret; }

More flexible typing through type parameters

35

StrongAspectJ, De Fraine et al., AOSD 08

slide-90
SLIDE 90

Supporting logging-like concerns through global pointcuts

36

<R> R around LogMe() { long timeBef = time(); R ret = proceed(); print(timeBef-time()); return ret; } class A { <R> exhibits R LogMe(): ... } class B { <R> exhibits R LogMe(): ... } class C { <R> exhibits R LogMe(): ... }

...

slide-91
SLIDE 91

Supporting logging-like concerns through global pointcuts

37

jpi <R> R LogMe(): call(* *(..)); class A { }

Introduces default:

class A { <R> exhibits R LogMe(): call(* *(..)); }

slide-92
SLIDE 92

Do allow for refinements...

38

class A { <R> exhibits R LogMe(); }

Seal a class: Add joinpoints:

class A { <R> exhibits R LogMe(): global() || set(* *); }

slide-93
SLIDE 93

Do allow for refinements...

39

class A { <R> exhibits R LogMe(); }

Seal a class: Refine joinpoints:

class A { <R> exhibits R LogMe(): global() && call(* foo()); }

slide-94
SLIDE 94

Result of typing rules

40

Invocation of a closure can never fail at runtime! Strong typing!

slide-95
SLIDE 95

Result of typing rules

40

Invocation of a closure can never fail at runtime!

slide-96
SLIDE 96

jpi ¡CheckingOut jpi ¡Buying jpi ¡Renting

Join Point Polymorphism

41

jpi ¡void ¡CheckingOut(float ¡price, ¡Customer ¡c)

slide-97
SLIDE 97

jpi ¡CheckingOut jpi ¡Buying

jpi ¡void ¡Buying(Item ¡i, ¡float ¡price, ¡Customer ¡cust) extends ¡CheckingOut(price,cust);

jpi ¡Renting

Join Point Polymorphism

41

jpi ¡void ¡CheckingOut(float ¡price, ¡Customer ¡c)

slide-98
SLIDE 98

jpi ¡CheckingOut jpi ¡Buying

jpi ¡void ¡Buying(Item ¡i, ¡float ¡price, ¡Customer ¡cust) extends ¡CheckingOut(price,cust);

jpi ¡Renting

Join Point Polymorphism

41

jpi ¡void ¡CheckingOut(float ¡price, ¡Customer ¡c)

“width subtyping”

slide-99
SLIDE 99

jpi ¡CheckingOut jpi ¡Buying

jpi ¡void ¡Buying(Item ¡i, ¡float ¡price, ¡Customer ¡cust) extends ¡CheckingOut(price,cust);

jpi ¡Renting

jpi ¡void ¡Renting(float ¡price, ¡int ¡amt, ¡Customer ¡c) extends ¡CheckingOut(price,c);

Join Point Polymorphism

41

jpi ¡void ¡CheckingOut(float ¡price, ¡Customer ¡c)

slide-100
SLIDE 100

The most specific advice gets executed.

Aspect Discount

around CheckingOut around Buying Join Point

Buying

Advice-dispatch semantics

jpi ¡CheckingOut jpi ¡Buying jpi ¡Renting

42

slide-101
SLIDE 101

The most specific advice gets executed.

Aspect Discount

around CheckingOut around Buying Join Point

Buying

Join Point

Renting

Advice-dispatch semantics

jpi ¡CheckingOut jpi ¡Buying jpi ¡Renting

42

slide-102
SLIDE 102

The most specific advice gets executed.

Aspect Discount

around CheckingOut around Buying Join Point

Buying

Join Point

Renting

Advice-dispatch semantics

jpi ¡CheckingOut jpi ¡Buying jpi ¡Renting

42

slide-103
SLIDE 103

NO depth subtyping

43

jpi ¡void ¡CheckingOut(Customer ¡c) jpi ¡void ¡GoodCheckout(GoodCustomer ¡c) ¡ ¡extends ¡CheckingOut(c);

slide-104
SLIDE 104

NO depth subtyping

43

jpi ¡void ¡CheckingOut(Customer ¡c) jpi ¡void ¡GoodCheckout(GoodCustomer ¡c) ¡ ¡extends ¡CheckingOut(c);

slide-105
SLIDE 105

NO depth subtyping

43

jpi ¡void ¡CheckingOut(Customer ¡c) jpi ¡void ¡GoodCheckout(GoodCustomer ¡c) ¡ ¡extends ¡CheckingOut(c);

¡ ¡void ¡around ¡CheckingOut(float ¡price, ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡Customer ¡cus){ proceed(price, ¡new ¡BadCustomer()); ¡}

  • Asp. A
slide-106
SLIDE 106

NO depth subtyping

43

jpi ¡void ¡CheckingOut(Customer ¡c) jpi ¡void ¡GoodCheckout(GoodCustomer ¡c) ¡ ¡extends ¡CheckingOut(c);

¡ ¡void ¡around ¡CheckingOut(float ¡price, ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡Customer ¡cus){ proceed(price, ¡new ¡BadCustomer()); ¡} ¡ ¡void ¡around ¡GoodCheckout(float ¡price, ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡GoodCustomer ¡cus){ ¡... ¡}

  • Asp. A
  • Asp. B
slide-107
SLIDE 107

NO depth subtyping

43

jpi ¡void ¡CheckingOut(Customer ¡c) jpi ¡void ¡GoodCheckout(GoodCustomer ¡c) ¡ ¡extends ¡CheckingOut(c);

¡ ¡void ¡around ¡CheckingOut(float ¡price, ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡Customer ¡cus){ proceed(price, ¡new ¡BadCustomer()); ¡} ¡ ¡void ¡around ¡GoodCheckout(float ¡price, ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡GoodCustomer ¡cus){ ¡... ¡}

  • Asp. A
  • Asp. B
slide-108
SLIDE 108

Only apparent solution

44

Forbid re-assignment of proceed values e.g. Ptolemy, see Session 3

slide-109
SLIDE 109

Static overloading

45

jpi ¡void ¡CheckingOut(Customer ¡c) jpi ¡void ¡CheckingOut(float ¡price, ¡Customer ¡c)

slide-110
SLIDE 110

Feature summary

46

JPIs as method signatures preserves lexical scoping CJPs when pointcut awkward Invariant typing (args, ret, exceptions) no more ClassCastExceptions Invariant pointcuts no more ClassCastExceptions Width subtyping better advice reuse Generic Type Parameters better advice reuse Global pointcuts fewer exhibit clauses

slide-111
SLIDE 111

Implementation

All implemented within abc Type-checking pass (JastAdd) All constructs flattened into plain AJ CJPs extracted into methods Associate correct pointcut with each advice Resulting runtime overhead: Zero!

47

Thanks Milton!

slide-112
SLIDE 112

Closely Related Work

Pointcut Interfaces (Gudmundson & Kiczales) refactoring only, no language support IIIA (Steimann et al.) First attempt to de-couple aspects from base code through types Ptolemy Only explicit events Hence no quantification (incl. global) No re-assignment of proceed values Hence: depth subtyping

48

slide-113
SLIDE 113

Evaluation

49

Study subjects: AJHotDraw, Glassbox, SpaceWar, LawOfDemeter (LoD) JPIs applicable in all cases Subtyping surprisingly useful (e.g. Glassbox) Generics avoid most redefinitions Global Pointcuts really useful for LoD

slide-114
SLIDE 114

50

http:/ /bodden.de/jpi

slide-115
SLIDE 115

50

http:/ /bodden.de/jpi

slide-116
SLIDE 116

50

http:/ /bodden.de/jpi

slide-117
SLIDE 117

Open problems

51

Pointcuts in classes defeat the purpose of quantification => Lift “exhibits” declaration to modules What about inter-type declarations? Interplay with execution layers/membranes (see next talk)

slide-118
SLIDE 118

52

Class ¡C

advice join ¡point (shadow)

jpi

pointcut

exhibit

Aspect ¡A cjp

http:/ /bodden.de/jpi http:/ /bodden.de/cjp

Separate evolution though strong typing