+ All Categories
Home > Documents > Invariants for Non-Hierarchical Object Structures Ronald Middelkoop, Kees Huizing, Ruurd Kuiper and...

Invariants for Non-Hierarchical Object Structures Ronald Middelkoop, Kees Huizing, Ruurd Kuiper and...

Date post: 21-Dec-2015
Category:
View: 222 times
Download: 0 times
Share this document with a friend
48
Invariants for Non-Hierarchical Object Structures Ronald Middelkoop, Kees Huizing, Ruurd Kuiper and Erik Luit
Transcript

Invariants for Non-Hierarchical Object Structures

Ronald Middelkoop, Kees Huizing, Ruurd Kuiper and

Erik Luit

2

Ronald Middelkoop

Overview

• Setting: Sequential Object-Oriented Development

• Classical Local Invariants

• Advantages of invariants

• Non-local Invariants

– Methods that re-establish an invariant

– Information Hiding

• Conclusions

3

Ronald Middelkoop

Visible state semantics:After an object’s creation, its invariant I holds in every visible state

Classical Local Invariants

Class C

int i;

C() {…}

int getI() {…}

void setI(int newI) {…}

inv this.i > 2;

Visible state: pre- or post-state of a method execution

4

Ronald Middelkoop

Classical Local Invariants

Theorem:After an object’s creation, its invariant I holds in every visible state, when

• The constructor of that object establishes I• All methods in the program preserve I• No method is called while I is invalid

Class C

int i;

C() {…}

int getI() {…}

void setI(int newI) {…}

inv this.i > 2;

Visible state: pre- or post-state of a method execution

5

Ronald Middelkoop

Classical Local Invariants

Theorem:After an object’s creation, its invariant I holds in every visible state, when

• The constructor of that object establishes I• All methods in the program preserve I• No method is called while I is invalid

Class C

int i;

C() { pre: true; post: true; impl: this.i = 4;}

int getI() {…}

void setI(int newI) {…}

inv this.i > 2;

Visible state: pre- or post-state of a method execution

6

Ronald Middelkoop

Classical Local Invariants

Theorem:After an object’s creation, its invariant I holds in every visible state, when

• The constructor of that object establishes I• All methods in the program preserve I• No method is called while I is invalid

Class C

int i;

C() {…}

int getI() { pre: true; post: result == this.i; impl: return this.i;}

void setI(int newI) {…}

inv this.i > 2;

Visible state: pre- or post-state of a method execution

7

Ronald Middelkoop

Classical Local Invariants

Theorem:After an object’s creation, its invariant I holds in every visible state, when

• The constructor of that object establishes I• All methods in the program preserve I• No method is called while I is invalid

Class C

int i;

C() {…}

int getI() { pre: true; post: result == this.i; impl: return this.i;}

void setI(int newI) { pre: newI > 2; post: this.i == newI; impl: this.i = newI;

}

inv this.i > 2;

Visible state: pre- or post-state of a method execution

8

Ronald Middelkoop

Advantages of Invariants

Class C

int i;

C() {…}

int getI() {…}

void setI(int newI) {…}

inv this.i > 2;

int m() { pre: true; post: result > 4; impl: return this.i +2;}

9

Ronald Middelkoop

Advantages of Invariants

Class C

int i;

C() {…}

int getI() {…}

void setI(int newI) {…}

int m() { pre: true; post: result > 4; impl: return this.i +2;}

m relies on i > 2

10

Ronald Middelkoop

Advantages of Invariants

Class C

int i;

C() {…}

int getI() {…}

void setI(int newI) {…}

int m() { pre: this.i > 2; post: result > 4; impl: return this.i +2;}

m relies on i > 2 m requires i > 2

11

Ronald Middelkoop

Advantages of Invariants

Class C

int i;

C() {…}

int getI() {…}

void setI(int newI) {…}

useC relies on c.i > 2

int m() { pre: this.i > 2; post: result > 4; impl: return this.i +2;}

Class D

int useC() { pre: true; post: result > 4; impl: return this.c.getI() + 2;}

C c;

inv this.c != null;

12

Ronald Middelkoop

Advantages of Invariants

Class C

int i;

C() {…}

int getI() {…}

void setI(int newI) {…}

Class D

int useC() { pre: this.c.i > 2; post: result > 4; impl: return this.c.getI() + 2;}

C c;

useC relies on c.i > 2 useC requires c.i > 2

inv this.c != null;

int m() { pre: this.i > 2; post: result > 4; impl: return this.i +2;}

13

Ronald Middelkoop

Advantages of Invariants

Class D

int useC() { pre: this.c.i > 2; post: result > 4; impl: return this.c.getI() + 2;}

C c;

Class E

int useUseC() { pre: this.d != null; post: result > 8; impl: return this.d.useC() + 4;}

D d;

useUseC calls d.useC() useC requires c.i > 2 useUseC has to establish d.c.i > 2

inv this.c != null;

14

Ronald Middelkoop

Advantages of Invariants

Class D

int useC() { pre: this.c.i > 2; post: result > 4; impl: return this.c.getI() + 2;}

C c;

Class E

int useUseC() { pre: this.d != null this.d.c.i > 2; post: result > 8; impl: return this.d.useC() + 4;}

D d;

useUseC calls d.useC() useC requires c.i > 2 useUseC has to establish d.c.i > 2 useUseC requires d.c.i > 2

inv this.c != null;

15

Ronald Middelkoop

Advantages of Invariants

Class D

int useC() { pre: this.c.i > 2; post: result > 4; impl: return this.c.getI() + 2;}

C c;

Class E

int useUseC() { pre: this.d != null this.d.c.i > 2; post: result > 8; impl: return this.d.useC() + 4;}

D d;

The invariant property propagates throughout the specification

inv this.c != null;

16

Ronald Middelkoop

Advantages of Invariants

Class D

int useC() { pre: this.c.i > 2; post: result > 4; impl: return this.c.getI() + 2;}

C c;

Class E

int useUseC() { pre: this.d != null this.d.c.i > 2; post: result > 8; impl: return this.d.useC() + 4;}

D d;

Advantage 1: Significant reduction in specification overhead

Advantage 2: Re-implementations of a method can rely on a different set of invariants

inv this.c != null;

17

Ronald Middelkoop

Advantages of Invariants

Sufficient:

The verifier of a method M that relies on an invariant I can

– Assume that I holds when M is called

– Deduce if a method M’ that is called by M preserves I

Advantage 1: Significant reduction in specification overhead

Advantage 2: Re-implementations of a method can rely on a different set of invariants

18

Ronald Middelkoop

Non-local Invariants

int d;

void setD(int newD) { pre: true; post: this.d == newD; impl: this.d = newD;}

CSubject1

Class CSubject Class CObserver

CSubject cs;

CObserver1

CObserver(CSubject toObs) {…}

int getVal() { pre: true; post: return == f(this.cs.d); impl: int i = this.cs.getD();

return f(i); //pseudocode}

inv this.cs != null;

void getD() {…}

19

Ronald Middelkoop

Non-local Invariants

int d;

void setD(int newD) { pre: true; post: this.d == newD; impl: this.d = newD;}

CSubject1

Class CSubject Class CObserver

CSubject cs;

int i;

CObserver1

CObserver(CSubject toObs) {…}

int getVal() { pre: true; post: return == f(this.cs.d); impl: return this.i;}

inv this.cs != null;

void getD() {…}

20

Ronald Middelkoop

Non-local Invariants

int d;

void setD(int newD) { pre: true; post: this.d == newD; impl: this.d = newD;}

Class CSubject Class CObserver

CSubject cs;

int i;

CObserver(CSubject toObs) {…}

int getVal() { pre: true; post: return == f(this.cs.d); impl: return this.i;}

inv this.i == f(this.cs.d);

inv this.cs != null;

void getD() {…}

• The constructor establishes I• All methods in the program preserve I• No method is called while I is invalid

CObserver X • X.cs ≠ this “invariant of X still holds after assignment”

21

Ronald Middelkoop

inv this.i == f(this.cs.d);

inv this == this.cs.co;

inv this.i == f(this.cs.d);

inv this.cs != null;

Non-local Invariants

int d;

CObserver co;

void setD(int newD) { pre: true; post: this.d == newD; impl: this.d = newD;}

Class CSubject Class CObserver

CSubject cs;

int i;

CObserver(CSubject toObs) {…}

int getVal() { pre: true; post: return == f(this.cs.d); impl: return this.i;}

void getD() {…}

• The constructor establishes I• All methods in the program preserve I• No method is called while I is invalid void update() {

post: this.i == f(this.cs.d);}

CObserver X • X.cs ≠ this “invariant of X still holds after assignment”

CObserver X • X.cs = this this.co = X

22

Ronald Middelkoop

Non-local Invariants

int d;

CObserver co;

void setD(int newD) { pre: true; post: this.d == newD; impl: this.d = newD;

if (this.co != null) { this.co.update();}

}

Class CSubject Class CObserver

CSubject cs;

int i;

CObserver(CSubject toObs) {…}

int getVal() { pre: true; post: return == f(this.cs.d); impl: return this.i;}void getD() {…}

• The constructor establishes I• All methods in the program preserve I• No method is called while I is invalid

void update() { post: this.i == f(this.cs.d);}

inv this.i == f(this.cs.d);

inv this == this.cs.co;

23

Ronald Middelkoop

inv this.i == f(this.cs.d);

inv this == this.cs.co;

Non-local Invariants

int d;

CObserver co;

void setD(int newD) { pre: true; post: this.d == newD; impl: this.d = newD;

if (this.co != null) { this.co.update();}

}

Class CSubject Class CObserver

CSubject cs;

int i;

CObserver(CSubject toObs) {…}

int getVal() { pre: true; post: return == f(this.cs.d); impl: return this.i;}void getD() {…}

• The constructor establishes I• All methods in the program preserve I• No method is called while I is invalid

void update() { inc: this; post: this.i == f(this.cs.d);}

24

Ronald Middelkoop

Theorem:

If, for any invariant I of any object,

– The constructor of that object establishes I

– All methods in the program preserve I

– While I is invalid, any method that is called specifies it doesn’t

rely on I

Then, for any method M, for any invariant I of any allocated object,

– Unless M is the constructor of that object

, I holds when M is called

– When I holds when a method M’ is called by M, I holds when M’

terminates

Theorem:

If, for any invariant I of any object,

– The constructor of that object establishes I

– All methods in the program preserve I

– While I is invalid, any method that is called specifies it doesn’t

rely on I

Then, for any method M, for any invariant I of any allocated object,

– Unless M is the constructor of that object

, I holds when M is called

– I holds when a method M’ called by M terminates

Theorem:

If, for any invariant I of any object,

– The constructor of that object establishes I

– All methods in the program preserve I

– While I is invalid, any method that is called specifies it doesn’t

rely on I

Then, for any method M, for any invariant I of any allocated object,

– or specifies

that it doesn’t rely on I

Theorem:

If, for any invariant I of any object,

– The constructor of that object establishes I

– All methods in the program preserve I

– While I is invalid, no method is called

Then, for any method M, for any invariant I of any allocated

object,

– Unless M is the constructor of that object, I holds when M

is called

– I holds when a method M’ called by M terminates

Theorem:

If, for any invariant I of any object,

– The constructor of that object establishes I

– All methods in the program preserve I

– While I is invalid,

Then, for any method M, for any invariant I of any allocated

object,

– Unless M is the constructor of that object, I holds when M

is called

– I holds when a method M’ called by M terminates

Theorem:

If, for any invariant I of any object,

– The constructor of that object establishes I

– All methods in the program preserve I

– While I is invalid, any method that is called specifies it doesn’t

rely on I

Non-local Invariants with inc

25

Ronald Middelkoop

Non-local Invariants with inc

int d;

CObserver co;

void setD(int newD) { pre: true; post: this.d == newD; impl: this.d = newD;

if (this.co != null) { this.co.update();}

}

Class CSubject Class CObserver

CSubject cs;

int i;

CObserver(CSubject toObs) {…}

int getVal() {…}

void getD() {…}

void update() { inc: this; post: this.i == f(this.cs.d);}

inv this.i == f(this.cs.d);

inv this == this.cs.co;

26

Ronald Middelkoop

Non-local Invariants with inc

int d;

CObserver co;

void setD(int newD) { pre: true; post: this.d == newD; impl: this.d = newD;

if (this.co != null) { this.co.update();}

}

Class CSubject Class CObserver

CSubject cs;

int i;

CObserver(CSubject toObs) {…}

int getVal() {…}

void getD() {…}

void update() { inc: this; post: this.i == f(this.cs.d); impl: int d = this.cs.getD();

this.i = f(d);}

inv this.i == f(this.cs.d);

inv this == this.cs.co;

• Update relies on this.cs ≠ null, which follows from this = this.cs.co

27

Ronald Middelkoop

Non-local Invariants with inc

int d;

CObserver co;

void setD(int newD) { pre: true; post: this.d == newD; impl: this.d = newD;

if (this.co != null) { this.co.update();}

}

Class CSubject Class CObserver

CSubject cs;

int i;

CObserver(CSubject toObs) {…}

int getVal() {…}

void getD() {…}

void update() { inc: this; post: this.i == f(this.cs.d); impl: int d = this.cs.getD();

this.i = f(d);}

• Update relies on this.cs ≠ null, which follows from this = this.cs.co

inv I def this.i == f(this.cs.d);

inv J def this == this.cs.co;

28

Ronald Middelkoop

Non-local Invariants with inc

int d;

CObserver co;

void setD(int newD) { pre: true; post: this.d == newD; impl: this.d = newD;

if (this.co != null) { this.co.update();}

}

Class CSubject Class CObserver

CSubject cs;

int i;

CObserver(CSubject toObs) {…}

int getVal() {…}

void getD() {…}

void update() { inc: I(this); post: this.i == f(this.cs.d); impl: int d = this.cs.getD();

this.i = f(d);}

• Update relies on this.cs ≠ null, which follows from this = this.cs.co

inv I def this.i == f(this.cs.d);

inv J def this == this.cs.co;

• While I is invalid, any method that is called specifies it doesn’t rely on I

29

Ronald Middelkoop

inv I def this.i == f(this.cs.d);

inv J def this == this.cs.co;

Non-local Invariants with inc

int d;

CObserver co;

void setD(int newD) { pre: true; post: this.d == newD; impl: this.d = newD;

if (this.co != null) { this.co.update();}

}

Class CSubject Class CObserver

CSubject cs;

int i;

CObserver(CSubject toObs) {…}

int getVal() {…}

void getD() { inc: I(this.co); impl: return this.d;}

void update() { inc: I(this); post: this.i == f(this.cs.d); impl: int d = this.cs.getD();

this.i = f(d);}

• While I is invalid, any method that is called specifies it doesn’t rely on I

30

Ronald Middelkoop

inv I def this.i == f(this.cs.d);

Non-local Invariants with inc

int d;

ONode on;

void setD(int newD) { …}

Class CSubject

CSubject cs;

int i;

CObserver(CSubject toObs) {…}

int getVal() {…}

void getD() {…}

void update() {…}

Class ONode

CObserver obs;

ONode next;

inv this.obs != null;

Class CObserver

31

Ronald Middelkoop

Non-local Invariants with inc

int d;

ONode on;

void setD(int newD) { this.d = newD; Onode iter = on; while (iter != null) { iter.obs.update(); iter = iter.next; }}

Class CSubject

void getD() {…}

Class ONode

CObserver obs;

ONode next;

inv this.obs != null;

inv I def this.i == f(this.cs.d);

CSubject cs;

int i;

CObserver(CSubject toObs) {…}

int getVal() {…}

void update() {…}

Class CObserver

32

Ronald Middelkoop

inv I def this.i == f(this.cs.d);

inv J def i • this == this.cs.on.nexti.obs;

Non-local Invariants with inc

int d;

ONode on;

void setD(int newD) { this.d = newD; Onode iter = on; while (iter != null) { iter.obs.update(); iter = iter.next; }}

Class CSubject Class CObserver

CSubject cs;

int i;

CObserver(CSubject toObs) {…}

int getVal() {…}

void getD() {…}void update() {…}

Class ONode

CObserver obs;

ONode next;

inv this.obs != null;

33

Ronald Middelkoop

void update() { inc: (CObserver, I, this == inc) post: this.i == f(this.cs.d);}

void update() { inc: (CObserver, I, this.cs == inc.cs) post: this.i == f(this.cs.d);}

void update() { inc: I(this) post: this.i == f(this.cs.d);}

void update() { inc: (CObserver, I, true) post: this.i == f(this.cs.d);}

inv I def this.i == f(this.cs.d);

inv J def i • this == this.cs.on.nexti.obs;

Non-local Invariants with inc

Class CObserver

CSubject cs;

int i;

CObserver(CSubject toObs) {…}

int getVal() {…}

Class ONode

CObserver obs;

ONode next;

inv this.obs != null;

void M(p_1, …,p_n) { inc: (C, I, P), (C’, I’, P’), …}

int d;

ONode on;

void setD(int newD) { this.d = newD; Onode iter = on; while (iter != null) { iter.obs.update(); iter = iter.next; }}

Class CSubject

void getD() {…}

34

Ronald Middelkoop

Information Hiding

Want Subject to work with different kinds of

Observers (simultaneously)

Concrete Observer(s) should be hidden from

Concrete Subject

Then: developing new observers doesn’t affect

the implementation, specification or verification

of the Concrete Subject.

35

Ronald Middelkoop

Information Hiding

inv I def this.i == f(this.cs.d);

inv J def this == this.cs.co;

int d;

CObserver co;

void setD(int newD) { pre: true; post: this.d == newD; impl: this.d = newD;

if (this.co != null) { this.co.update();}

}

Class CSubject Class CObserver

CSubject cs;

int i;

CObserver(CSubject toObs) {…}

int getVal() {…}

void getD() {…}

void update() { inc: I(this); post: this.i == f(this.cs.d); impl: int d = this.cs.getD();

this.i = f(d);}

Invariant I of CObserver not visible to CSubject

36

Ronald Middelkoop

Information Hiding

inv I def this.i == f(this.cs.d);

inv J def this == this.cs.co;

int d coop I(this.co);

CObserver co;

void setD(int newD) { pre: true; post: this.d == newD; impl: this.d = newD;

if (this.co != null) { this.co.update();}

}

Class CSubject Class CObserver

CSubject cs;

int i;

CObserver(CSubject toObs) {…}

int getVal() {…}

void getD() {…}

void update() { inc: I(this); post: this.i == f(this.cs.d); impl: int d = this.cs.getD();

this.i = f(d);}

Invariant I of CObserver not visible to CSubject

37

Ronald Middelkoop

Information Hiding

inv I def this.i == f(this.cs.d);

inv J def this == this.cs.co;

int d coop I(this.co);

CObserver co coop I(this.co), J(this.co);

void setD(int newD) { pre: true; post: this.d == newD; impl: this.d = newD;

if (this.co != null) { this.co.update();}

}

Class CSubject Class CObserver

CObserver(CSubject toObs) {…}

int getVal() {…}

void getD() {…}

void update() { inc: I(this); post: this.i == f(this.cs.d); impl: int d = this.cs.getD();

this.i = f(d);}

CSubject cs coop I(this), J(this);

int i coop I(this);

Invariant I of CObserver not visible to CSubject

38

Ronald Middelkoop

Information Hiding

inv I def this.i == f(this.cs.d);

inv J def this == this.cs.co;

int d coop I(this.co);

CObserver co coop I(this.co), J(this.co);

void setD(int newD) { pre: true; post: this.d == newD; impl: this.d = newD;

if (this.co != null) { this.co.update();}

}

Class CSubject Class CObserver

CObserver(CSubject toObs) {…}

int getVal() {…}

void getD() {…}

void update() { inc: I(this); post: I(this); impl: int d = this.cs.getD();

this.i = f(d);}

CSubject cs coop I(this), J(this);

int i coop I(this);

Invariant I of CObserver not visible to CSubject

39

Ronald Middelkoop

Information Hiding

Observer o coop I(this.o), J(this.o);

Class Subject

int d coop I(this.o);

Class CSubject extends Subject

void setD(int newD) { post: this.d == newD; impl: this.d = newD;

if (this.o != null) { this.o.update();}

}

Interface Observer

abstract Subject s coop J(this);

abstract inv I;

inv J def this == this.s.o;

abstract void update() { inc: I(this); post: I(this);}

Class CObserver implements Observer

40

Ronald Middelkoop

Information Hiding

Interface Observer

abstract Subject s coop J(this);

abstract inv I;

inv J def this == this.s.o;

abstract void update() { inc: I(this); post: I(this);}

Class CObserver implements Observer

int i coop I(this);

CSubject cs coop I(this);

def s by cs;def I by this.i == f(this.cs.d) J(this);

CObserver(CSubject toObs) {…}

void update() { impl: int d = this.cs.getD();

this.i = f(d);}

41

Ronald Middelkoop

Conclusions• inc allows one to call methods that re-

establish invariants

• coop allows one to make explicit which

invariants might be invalidated when a field is

assigned to

• Together, they allow the full, modular

specification of complex, non-hierarchical

designs like the Observer Pattern

Future Work:

• Complement with other solutions, in particular

hierarchical ones

• Combine with other ways of making

dependencies explicit

50

Ronald Middelkoop

Proof Obligations

{P0} r.f := E; {P1} S2; {P2}

if (b) {

{P3} S3; {P4}

} else {

{P6} S4; {P7}

} {P8}

while (b) {

{P9} S5; {P10}

} {P11}

M() { …

}

int f coop I(r)

int f coop (C,I,P)

int f coop (C, I, dep = r)

51

Ronald Middelkoop

Proof Obligations

{P0’ (X = null P[X/dep])} r.f := E; {P1}

S2; {P2}

if (b) {

{P3} S3; {P4}

} else {

{P6} S4; {P7}

} {P8}

while (b) {

{P9} S5; {P10}

} {P11}

M() { …

}

int f coop I(r)

int f coop (C,I,P)

int f coop (C, I, dep = r)

X represents an arbitrary C-object that the assignment might make inconsistent

52

Ronald Middelkoop

Proof Obligations

{P0’ (X = null P[X/dep])} r.f := E; {P1} S2;

{P2}

if (b) {

{P3} S3; {P4}

} else {

{P6} S4; {P7}

} {P8}

while (b) {

{P9} S5; {P10}

} {P11}

M() { …

}

int f coop I(r)

int f coop (C,I,P)

int f coop (C, I, dep = r)

? P1 I(X) ?

53

Ronald Middelkoop

Proof Obligations

{P0’ (X = null P[X/dep])} r.f := E; {P1} S2; {P2}

if (b) {

{P3} S3; {P4}

} else {

{P6} S4; {P7}

} {P8}

while (b) {

{P9} S5; {P10}

} {P11}

M() { …

}

int f coop I(r)

int f coop (C,I,P)

int f coop (C, I, dep = r)

? S2 Method call ?

54

Ronald Middelkoop

Proof Obligations

{P0’ (X = null P[X/dep])} r.f := E; {P1} S2;

{P2}

if (b) {

{P3} S3; {P4}

} else {

{P6} S4; {P7}

} {P8}

while (b) {

{P9} S5; {P10}

} {P11}

M() { …

}

int f coop I(r)

int f coop (C,I,P)

int f coop (C, I, dep = r)

? P2 I(X) ?

55

Ronald Middelkoop

Proof Obligations

{P0’ (X = null P[X/dep])} r.f := E; {P1} S2;

{P2}

if (b) {

{P3} S3; {P4}

} else {

{P6} S4; {P7}

} {P8}

while (b) {

{P9} S5; {P10}

} {P11}

M() { …

}

int f coop I(r)

int f coop (C,I,P)

int f coop (C, I, dep = r)

Don’t know which branch is taken;Branches might contain calls

56

Ronald Middelkoop

Proof Obligations

{P0’ (X = null P[X/dep])} r.f := E; {P1} S2;

{P2}

if (b) {

{P3} S3; {P4}

} else {

{P6} S4; {P7}

} {P8}

while (b) {

{P9} S5; {P10}

} {P11}

M() { …

}

int f coop I(r)

int f coop (C,I,P)

int f coop (C, I, dep = r)

Don’t know if while is executed;Body might contain calls


Recommended