invariants for non-hierarchical object structures ronald middelkoop, kees huizing, ruurd kuiper and...
Post on 21-Dec-2015
222 Views
Preview:
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
top related