Semantic Casts: Contracts and Structural Subtyping in a Nominal - - PowerPoint PPT Presentation

semantic casts
SMART_READER_LITE
LIVE PREVIEW

Semantic Casts: Contracts and Structural Subtyping in a Nominal - - PowerPoint PPT Presentation

Semantic Casts: Contracts and Structural Subtyping in a Nominal World Robby Findler University of Chicago Matthew Flatt University of Utah Matthias Felleisen Northeastern University 1 Component marketplace - McIlroy's vision (1969) -


slide-1
SLIDE 1

Semantic Casts:

Contracts and Structural Subtyping in a Nominal World

Robby Findler University of Chicago Matthew Flatt University of Utah Matthias Felleisen Northeastern University

1

slide-2
SLIDE 2

Component marketplace

  • McIlroy's vision (1969)
  • Independent developers produce

pieces of programs (components)

  • 3rd parties compose the components
  • Economic benefits: division of labor and competition
  • Software construction: merely plug & play

2

slide-3
SLIDE 3

3

slide-4
SLIDE 4

4

slide-5
SLIDE 5

5

slide-6
SLIDE 6

6

slide-7
SLIDE 7

7

slide-8
SLIDE 8

8

slide-9
SLIDE 9

9

slide-10
SLIDE 10

10

slide-11
SLIDE 11

What is a contract?

  • Agreement between two components
  • Only allows certain patterns of interactions

11

slide-12
SLIDE 12

Why check contracts?

  • Find faulty components
  • Accountability supports

component economy

12

slide-13
SLIDE 13

Contracts [Beugnard et al. 1999]

  • Syntactic: types

int f(int[] x, int k)

  • Semantic level 1: behavioral

int f(int[] x, int k) // 0 <= k < x.length()

  • Semantic level 2: sequencing, concurrency

finalize is called for all objects

  • Quality of service: space, time

web server handles at least 1000 GET/sec

13

slide-14
SLIDE 14

Behavioral contract desiderata

  • Simplicity (dynamic enforcement)
  • Precise enforcement (no false pos/neg)
  • Blame

14

slide-15
SLIDE 15

Behavioral contract history

  • Parnas: 1972
  • Luckham: ANNA for Ada
  • Meyer: Eiffel
  • ...

15

slide-16
SLIDE 16

Queues: an example

16

slide-17
SLIDE 17

Queue class Q implements IQueue { void enq(int X) {...} int deq() {...} boolean empty() {...} }

17

slide-18
SLIDE 18

// @pre !this.empty() // @post !this.empty() Queue class Q implements IQueue { void enq(int X) {...} int deq() {...} boolean empty() {...} }

18

slide-19
SLIDE 19

// @pre !this.empty() // @post !this.empty() Queue class Q implements IQueue { void enq(int X) {...} int deq() {...} boolean empty() {...} } Good client IQueue q = new Q(); q.enq(1); q.deq();

19

slide-20
SLIDE 20

// @pre !this.empty() // @post !this.empty() Queue class Q implements IQueue { void enq(int X) {...} int deq() {...} boolean empty() {...} } Good client IQueue q = new Q(); q.enq(1); q.deq(); Bad client IQueue q = new Q(); q.deq(); q.enq(1);

20

slide-21
SLIDE 21

// @pre !this.empty() // @post !this.empty() Queue class Q implements IQueue { void enq(int X) {...} int deq() {...} boolean empty() {...} } Good client IQueue q = new Q(); q.enq(1); q.deq(); Bad client IQueue q = new Q(); q.deq(); q.enq(1); Blame q.deq(); in Bad Client

21

slide-22
SLIDE 22

Queue with observer please: a "good" Observer class Q implements IQueue { Obs o; void enq(int X) {...} // @post !this.empty() // effect: o.onEnq(this) int deq() {...} // @pre !this.empty() // effect: o.onDeq(this) void register(Obs _o) {o = _o;} // }

22

slide-23
SLIDE 23

Good observer class GoodO implements Obs { void init() {...} void onEnq(IQueue q) {...} // @post !q.empty() void onDeq(IQueue q) {...} }

23

slide-24
SLIDE 24

Good observer class GoodO implements Obs { void init() {...} void onEnq(IQueue q) {...} // @post !q.empty() void onDeq(IQueue q) {...} } Bad Observer class BadO implements Obs { void init() {...} void onEnq(IQueue q) { q.deq() } void onDeq(IQueue q) {...} }

24

slide-25
SLIDE 25

Client Queue BadO

25

slide-26
SLIDE 26

Client links BadO and Queue Client Queue BadO

26

slide-27
SLIDE 27

Queue post-condition failure Client Queue BadO

27

slide-28
SLIDE 28

Who to blame? Client Queue BadO

28

slide-29
SLIDE 29

Who to blame? Client Queue BadO

  • Client combines mis-matched components
  • BadO violates informal contract
  • Queue is blamed

29

slide-30
SLIDE 30

Queue with observer please: a "good" Observer class Q implements IQueue { Obs o; void enq(int X) {...} // @post !this.empty() // effect: o.onEnq(this) int deq() {...} // @pre !this.empty() // effect: o.onDeq(this) void register(Obs _o) {o = _o;} // }

30

slide-31
SLIDE 31

@pre _o.onEnq(...) Queue with observer class Q implements IQueue { Obs o; void enq(int X) {...} // @post !this.empty() // effect: o.onEnq(this) int deq() {...} // @pre !this.empty() // effect: o.onDeq(this) void register(Obs _o) {o = _o;} // }

31

slide-32
SLIDE 32

Contracts in interfaces?

32

slide-33
SLIDE 33

Observer contracts interface Obs { void init(); void onEnq(IQueue q); // @post !q.empty() void onDeq(IQueue q); // @pre !q.empty() } Force observers to meet pre- and post-conditions that Queue needs

33

slide-34
SLIDE 34

Controlling BadO class BadO implements Obs { void init() {...} void onEnq(IQueue q) { q.deq() } void onDeq(IQueue q) {...} }

34

slide-35
SLIDE 35

// @post !q.empty() Controlling BadO class BadO implements Obs { void init() {...} void onEnq(IQueue q) { q.deq() } void onDeq(IQueue q) {...} }

35

slide-36
SLIDE 36

A A'

36

slide-37
SLIDE 37

A A'

37

slide-38
SLIDE 38

A A' A - A'

38

slide-39
SLIDE 39

A A' A - A'

39

slide-40
SLIDE 40

Queue Class class Q implements IQueue { ... } Positive Queue interface IPosQ { void enq(int X) {...} // @pre X >= 0 // @post !this.empty() int deq() {...} // @pre !this.empty() // @post @ret >= 0 }

40

slide-41
SLIDE 41

Queue Class class Q implements IQueue { ... } Positive Queue interface IPosQ { void enq(int X) {...} // @pre X >= 0 // @post !this.empty() int deq() {...} // @pre !this.empty() // @post @ret >= 0 }

41

slide-42
SLIDE 42

Nominal subtyping

  • Hierarchy explicit
  • Conventional OO PLs:

C++, C#, Eiffel, Java

Structural subtyping

  • Hierarchy implicit
  • Research OO PLs:

Moby, OML, OCaml, LOOM, PolyTOIL

42

slide-43
SLIDE 43

Nominal subtyping

  • Simple to implement
  • Simple type-error messages
  • Inhibits re-use

Structural subtyping

  • Harder to implement
  • Complex type-error messages
  • Permits flexible re-use

43

slide-44
SLIDE 44

QClass class Q implements IQueue { ... } IQueue interface IQueue { void enq(int X) {...} // @post !this.empty() int deq() {...} // @pre !this.empty() } IPosQ interface IPosQ { void enq(int X) {...} // @pre X >= 0 // @post !this.empty() int deq() {...} // @pre !this.empty() // @post @ret >= 0 }

44

slide-45
SLIDE 45

Structural Subtyping in an Nominal World

45

slide-46
SLIDE 46

semanticCast(obj, I, <fromStr>, <toStr>)

A structural subtype "cast"

46

slide-47
SLIDE 47

semanticCast(obj, I, <fromStr>, <toStr>)

The object that gets casted, now has additional contracts

47

slide-48
SLIDE 48

semanticCast(obj, I, <fromStr>, <toStr>)

The interface that describes the additional contracts

48

slide-49
SLIDE 49

semanticCast(obj, I, <fromStr>, <toStr>)

The name of the component where the object is from; Responsible for post-conds

49

slide-50
SLIDE 50

semanticCast(obj, I, <fromStr>, <toStr>)

The name of the component where the object is sent; Responsible for pre-conds

50

slide-51
SLIDE 51

semanticCast(obj, I, <fromStr>, <toStr>)

Result ensures I's contracts but otherwise identical to obj Has type I, even if obj doesn't

51

slide-52
SLIDE 52

A A' A - A'

52

slide-53
SLIDE 53

A A' A - A'

semanticCast (o,A, , )

53

slide-54
SLIDE 54

A A' A - A'

semanticCast (o,A, , ) semanticCast (o,A', , )

54

slide-55
SLIDE 55

<Queue> IQueue q = new Q(); <Client> q.enq(1); q.deq(); q.enq(-1); <PosQueue> q

55

slide-56
SLIDE 56

<Queue> IQueue q = new Q(); <Client> q.enq(1); q.deq(); q.enq(-1); <PosQueue> q

56

slide-57
SLIDE 57

<Queue> IQueue q = new Q(); semanticCast(q, IQueue, <Queue>, <PosQueue>) <Client> q.enq(1); q.deq(); q.enq(-1); semanticCast(q, IPosQ, <PosQueue>, <Client>) <PosQueue> q

57

slide-58
SLIDE 58

<Queue> IQueue q = new Q(); semanticCast(q, IQueue, <Queue>, <PosQueue>) <Client> q.enq(1); q.deq(); q.enq(-1); semanticCast(q, IPosQ, <PosQueue>, <Client>) <PosQueue> q

58

slide-59
SLIDE 59

<Queue> IQueue q = new Q(); semanticCast(q, IQueue, <Queue>, <PosQueue>) <Client> q.enq(1); q.deq(); q.enq(-1); semanticCast(q, IPosQ, <PosQueue>, <Client>) <PosQueue> q

59

slide-60
SLIDE 60

<Queue> IQueue q = new Q(); semanticCast(q, IQueue, <Queue>, <PosQueue>) <Client> q.enq(1); q.deq(); q.enq(-1); semanticCast(q, IPosQ, <PosQueue>, <Client>) <PosQueue> q

60

slide-61
SLIDE 61

Semantics of semanticCast

61

slide-62
SLIDE 62

Semantics of semanticCast

62

slide-63
SLIDE 63

Semantics of semanticCast

63

slide-64
SLIDE 64

Semantics of semanticCast

64

slide-65
SLIDE 65

Semantics of semanticCast

65

slide-66
SLIDE 66

Semantics of semanticCast

66

slide-67
SLIDE 67

Semantics of semanticCast

67

slide-68
SLIDE 68

Semantics of semanticCast

68

slide-69
SLIDE 69

semanticCast(o, I, <from>, <to>).m(o') = semanticCast(o.m(semanticCast o', J, <to>, <from>), K, <from>, <to>) interface I { K m(J x); } interface J { ... } interface K { ... }

69

slide-70
SLIDE 70

Implementation

  • Proxies
  • Construct new proxies

at method calls

70

slide-71
SLIDE 71

Wrap up

71

slide-72
SLIDE 72

Structural subtyping for contracts

  • Adds flexibility to conventional languages
  • Contracts still simple boolean expressions
  • Proper blame assignment
  • If a tree in the forest hasn't yet fallen,

it didn't make a sound

72

slide-73
SLIDE 73

Thank you.

73