Specification Strength and Substitutability

Specifications, continued
Review
Spec “A is stronger than B” means
For every implementation 
I
I
 satisfies A” implies 
“I
 satisfies B”
If the implementation satisfies the stronger spec (A), it satisfies the weaker (B)
The opposite is not necessarily true!
For every client 
C
C 
meets the obligations of B” implies “
C
 meets the obligations of A”
If C meets the weaker spec (B), it meets the stronger spec (A)
The opposite is not necessarily true
A 
larger world 
of implementations satisfy the weaker spec B than the
stronger spec A
Consequently, it is easier to implement a weaker spec!
Weaker specs require 
more
 AND/OR Weaker specs guarantee (promise) 
less
CSCI 2600 Spring 2021
2
Satisfaction of Specifications
I is an implementation and S is a specification
I satisfies S if
Every behavior of I is permitted by S
No behavior of I violates S
The statement “I is correct” is meaningless, but often used
If I does not satisfy S, either or both could be wrong
I does something that S doesn’t specify
S 
expects a result 
that I doesn’t produce
When I doesn’t satisfy S, i
t’s usually better to change the program rather than
the spec.
If spec is too complex modify spec
CSCI 2600 Spring 2021
3
Why Compare Specs?
Liskov Substitution Principle
We want to use a subclass method in place of superclass method
Spec of subclass method must be stronger
Or at least equally strong
Which spec is stronger?
A procedure satisfying a stronger spec can be used anywhere a weaker spec
is required.
Does the implementation satisfy the specification?
CSCI 2600 Spring 2021
4
Comparing Specifications
One way: by hand, examine each clause
Another way: logical formulas representing the spec
Use whichever is most convenient
Comparing specs enables reasoning about substitutability
CSCI 2600 Spring 2021
5
Exercise
 
Specification A:
requires
: 
a
 is non-null and 
value
 occurs in 
a
modifies
: none
effects
: none
returns
: the smallest index 
i
 such that 
a[i] = value
Specification B:
requires
:
 
a
 is non-null and 
value
 occurs in 
a
  // same as A
modifies
: none  // same as A
effects
: none   // same as A
returns
: 
i
 such that 
a[i] = value 
// fewer guarantees
 
Therefore, A is stronger.
In fact, A’s postcondition implies B’s postcondition
 
CSCI 2600 Spring 2021
6
Example
 
Specification B:
requires
: 
a
 is non-null and 
value
 occurs in 
a
modifies: 
none
effects:
 none
returns
: 
i
 such that 
a[i] = value
Specification A:
requires: 
a
 is non-null // fewer conditions!
modifies: 
none // same
effects: 
none // same
returns
: 
i
 such that 
a[i] = value
 if value occurs in 
a
 and
i = -1
 if value is not in 
a 
// guarantees more!
Therefore, A is stronger!
 
CSCI 2600 Spring 2021
7
Strong Versus Weak Specifications
double sqrt(double x)
Which are stronger?
CSCI 2600 Spring 2021
8
A.
@requires x>= 0
     @return y such that |y^2 – x| <= 1
B.
@requires none
     @return y such that |y^2 – x| <= 1
     @throws IllegalArgumentException if x < 0
C. @requires x>= 0
    @return y such that |y^2 – x| <= 0.1
Comparing Specifications
Most of our specification comparisons will be informal
A is stronger than B if
 
A’s precondition is weaker than B’s 
        (keeping postcondition the same)
-
Requires less of client
Or
A’s postcondition is stronger than B’s
 (keeping precondition the same)
-
Guarantees more to client
Or
A’s precondition is weaker than B’s
AND
A’s postcondition is stronger than B’s
Comparing by Logical Formulas
Specification S1 is stronger than S2 iff
For all implementations I, (I satisfies S1) => (I satisfies S2)
The set of implementations that satisfy S1 is a 
subset
 of the set of
implementations satisfying S2.
If each specification is a logical formula
S1 => S2
Comparison using logical formulas is precise but can be difficult
to carry out.
It is often difficult to express all preconditions and
postconditions with precise logical formulas!
CSCI 2600 Spring 2021
10
Implication Truth Table
CSCI 2600 Spring 2021
11
Comparing by Logical Formulas
S1 is stronger than S2
(x is an element of set of programs satisfying S1) => (x is an element of
the  set of programs satisfying S2)
the set of programs satisfying S1 is a subset of the set of programs
satisfying S2
"A is a subset of B" if and only if every element of 
A 
also belongs to 
B
An implementation I that satisfies S1 also satisfies S2
If (I satisfies S1) => (I satisfies S2) is false
Then S1 does not imply S2, or S1 is not stronger than S2.
If I does not satisfy S1, all bets are off. I might or might not satisfy S2.
See 
http://press.princeton.edu/chapters/s8898.pdf
CSCI 2600 Spring 2021
Comparing by Logical Formulas
Let 
 
Spec 
A
: {
P
A
} 
code
 {
Q
A
},
 
Spec 
B
: {
P
B
} 
code
 {
Q
B
}.
We say 
code
 satisfies a specification with precondition 
P
 and
postcondition 
Q
 iff  {
P
} 
code
 {
Q
} Hoare triple is true.
 
Do not confuse it with 
P => Q
.
 
e.g., { 
true
 } 
x = 1; 
{ 
x = 1 
} is true, but
 
          true => x = 1 
is false.
CSCI 2600 Spring 2021
13
Comparing by Logical Formulas
Let 
 
Spec 
A
: {
P
A
} 
code
 {
Q
A
},
 
Spec 
B
: {
P
B
} 
code
 {
Q
B
}.
The following are equivalent:
 P
B
 
=> P
A
 
and 
Q
A
 => Q
B
A
 is stronger than 
B
A => B
CSCI 2600 Spring 2021
14
Example Revisited: int find(int[] a, int val)
int find(int[] a, int value) {
   for (int i=0; i<a.length; i++) {
      if (a[i] == value) return i;
   }
   return -1;
}
Specification B:
requires
: 
a
 is non-null and 
value
 occurs in 
a
  
returns
: 
i
 such that 
a[i] = value
Specification A:
requires: 
a
 is non-null 
returns
: 
i
 such that 
a[i] = value
 or 
i = -1
 if
value is not in 
a
Be careful with specifications!
returns
: 
i
 such that 
a[i] = value
 or 
i = -1
 if
value
 is not in 
a
Let 
P 
= “val occurs in a”,
      
Q 
= “return i s.t. a[i] = val”
      
R 
= “return -1”
  
(P => Q) v (!P => R)
 
= 
 
(!P v Q) v (P v R)
 
= 
 
Q v R
or” would allow us to write a method that always returns -1!
Be careful with specifications!
returns
: 
i
 such that 
a[i] = value
 or 
i = -1
 if
value
 is not in 
a
W
e
 
r
e
a
l
l
y
 
m
e
a
n
:
 
i
 
s
u
c
h
 
t
h
a
t
 
a
[
i
]
 
=
 
v
a
l
u
e
 
i
f
 
v
a
l
u
e
i
s
 
i
n
 
a
,
 
A
N
D
 
i
 
=
 
-
1
 
i
f
 
v
a
l
u
e
 
i
s
 
n
o
t
 
i
n
 
a
.
P => Q ^ !P => R is equivalent to: 
(P ^ Q) v (!P ^ R) v (Q ^ R)
In our case,  “P 
=> Q ^ !P => R”  and  “(P ^ Q) v (!P ^ R)” are
equivalent since “Q^R” is false (return -1 and return a value >= 0
cannot both be true.)
So, we could also say: “(
i such that a[i] = value 
and
 value is in a)
or
 (i = -1 
and
 value is not in a)
”.
Example: int find(int[] a, int val)
 
Specification B:
requires
: 
a
 is non-null and 
val
 occurs in 
a
  
[
 
P
B 
]
returns
: 
i
 such that 
a[i] = val 
[
 
Q
B 
]
Specification A:
requires: 
a
 is non-null 
[
 
P
A 
]
returns
: 
i
 such that 
a[i] = val
 if value 
val 
occurs in 
a
 and
 -1
 if
value 
val 
does not occur in 
a 
[
 
Q
A 
]
Clearly, 
P
B
 => 
P
A
.
Q
A
 states 
val
 occurs in 
a
  =>  returns 
i
 such that 
a[i]=val 
AND 
val
does not occur in 
a
 =>  returns 
-1
Q
B
 can be logically rewritten as: “
val
 occurs in 
a
  =>  returns 
i
such that 
a[i]=val 
AND 
val
 does not occur in 
a
 =>  returns
anything
.” (violated precondition allows anything.)
CSCI 2600 Spring 2021
18
 
 
Comparing postconditions
Q
B
 (postcondition of Spec B)
i
 such that 
a[i] == value
 can be written (due to the precondition) as:
value
 is in 
a
 => 
i
 such that 
a[i] == value
&& 
value
 is not in 
a
 => true
Q
A
 (postcondition of Spec A)
value
 is in 
a
 => 
i
 such that 
a[i] == value
&& 
value
 is not in 
a => 
-1=i
Which is stronger, Q
B
 or Q
A
?
CSCI 2600 Spring 2021
19
Q
B
 and Q
A 
are 
NOT
 :
Q
B2
: {0 <= i < a.length}
Q
A2
: {-1 <= i < a.length}
For these, Q
B2
 => Q
A2
, i.e., Q
B2
 is stronger
Comparing by Logical Formulas
Let  
A
 = {
P
A
} 
code
 {
Q
A
},
       
B
 = {
P
B
} 
code
 {
Q
B
}      be Hoare triples.
A
 is stronger than 
B
 if and only if 
P
A
 
is weaker than 
P
B
and 
Q
A
 is stronger than 
Q
B
, i.e.,
A => B  <=
=>
 (P
B
 =>  P
A
 ^ Q
A
 => Q
B
)
.
A => B 
means that any 
code
 satisfying 
A
 also satisfies 
B
.
CSCI 2600 Spring 2021
20
Example: int find(int[] a, int val)
 
Specification B:
requires
: 
a
 is non-null and 
val
 occurs in 
a
  
[
 
P
B 
]
returns
: 
i
 such that 
a[i] = val 
[
 
Q
B 
]
Specification A:
requires: 
a
 is non-null 
[
 
P
A 
]
returns
: 
i
 such that 
a[i] = val
 if value 
val 
occurs in 
a
 and
 -1
 if
value 
val 
does not occur in 
a 
[
 
Q
A 
]
 
P
B
 requires more of the caller than P
A
. That is, 
P
B
 => 
P
A
.
Q
A
 promises more to the caller than Q
B
  (Q
B
 does not
promise anything if 
val
 does not occur in 
a
; e.g., code
satisfying B could return -99.).  That is, 
Q
A
 => 
Q
B
.
CSCI 2600 Spring 2021
21
Example: int find(int[] a, int val)
Specification B:
r
e
q
u
i
r
e
s
:
 
a
 
i
s
 
n
o
n
-
n
u
l
l
 
a
n
d
 
v
a
l
 
o
c
c
u
r
s
 
i
n
 
a
 
 
[
 
P
B
 
]
r
e
t
u
r
n
s
:
 
i
 
s
u
c
h
 
t
h
a
t
 
a
[
i
]
 
=
 
v
a
l
 
[
 
Q
B
 
]
Specification A:
r
e
q
u
i
r
e
s
:
 
a
 
i
s
 
n
o
n
-
n
u
l
l
 
[
 
P
A
 
]
r
e
t
u
r
n
s
:
 
i
 
s
u
c
h
 
t
h
a
t
 
a
[
i
]
 
=
 
v
a
l
 
i
f
 
v
a
l
 
o
c
c
u
r
s
 
i
n
 
a
 
a
n
d
 
 
 
-
1
 
i
f
v
a
l
 
d
o
e
s
 
n
o
t
 
o
c
c
u
r
 
i
n
 
a
 
[
 
Q
A
 
]
I
n
t
u
i
t
i
o
n
:
 
Q
B
 
s
h
o
u
l
d
 
r
e
a
l
l
y
 
b
e
 
t
h
o
u
g
h
t
 
o
f
 
a
s
:
  
i
 such that 
a[i] = val 
if 
val
 occurs in 
a
Thus, it
s still OK to substitute A for B.
CSCI 2600 Spring 2021
22
Exercise: int find(int[] a, int val)
Sort specifications in order of strength
Specification B:
r
e
q
u
i
r
e
s
:
 
a
 
i
s
 
n
o
n
-
n
u
l
l
 
a
n
d
 
v
a
l
 
o
c
c
u
r
s
 
i
n
 
a
 
 
[
 
P
B
 
]
r
e
t
u
r
n
s
:
 
i
 
s
u
c
h
 
t
h
a
t
 
a
[
i
]
 
=
 
v
a
l
 
[
 
Q
B
 
]
Specification A:
r
e
q
u
i
r
e
s
:
 
a
 
i
s
 
n
o
n
-
n
u
l
l
 
[
 
P
A
 
]
r
e
t
u
r
n
s
:
 
i
 
s
u
c
h
 
t
h
a
t
 
a
[
i
]
 
=
 
v
a
l
 
i
f
 
v
a
l
 
o
c
c
u
r
s
 
i
n
 
a
 
a
n
d
 
 
 
-
1
 
i
f
v
a
l
 
d
o
e
s
 
n
o
t
 
o
c
c
u
r
 
i
n
 
a
 
[
 
Q
A
 
]
Specification C:
r
e
q
u
i
r
e
s
:
 
n
o
n
e
 
[
 
P
C
 
]
r
e
t
u
r
n
s
:
 
i
 
s
u
c
h
 
t
h
a
t
 
a
[
i
]
 
=
 
v
a
l
 
i
f
 
v
a
l
 
o
c
c
u
r
s
 
i
n
 
a
 
a
n
d
 
 
 
-
1
 
i
f
v
a
l
 
d
o
e
s
 
n
o
t
 
o
c
c
u
r
 
i
n
 
a
 
[
 
Q
C
 
]
 
 
 
 
t
h
r
o
w
s
:
 
N
u
l
l
P
o
i
n
t
e
r
E
x
c
e
p
t
i
o
n
 
i
f
 
a
 
i
s
 
n
u
l
l
 
[
Q
C
 
]
CSCI 2600 Spring 2021
23
Converting PSoft Specs into Logical Formulas
PSoft specification
   requires:
 R
   modifies:
 M
   
effects:
 E
is equivalent to this logical formula
{R} 
code
 
{E ^
 (nothing but M is modified)}
throws
 and 
returns
 are absorbed into 
effects 
E
CSCI 2600 Spring 2021
24
Convert Spec to Formula, step 1: absorb
throws
 and 
returns
 into 
effects
PSoft specification convention
   
requires:
 (unchanged)
   
modifies:
 (unchanged)
   effects:
   
returns:
              absorbed into “effects”
   
throws:
CSCI 2600 Spring 2021
25
set
 method from 
java.util.ArrayList<T>
   
T set(int index, T element)
requires
: true
modifies
: this[index]
effects
:
 
this
post
[index] = element
throws
:
 
IndexOutOfBoundsException if index < 0 || index ≥ size
returns
:
 
this
pre
[index]
Absorb 
effects
, 
returns
 and 
throws
 into new 
effects:
E= if index < 0 || index ≥ size then 
  
 
throws IndexOutOfBoundsException 
  
else
  
this
post
[index] = element and returns this
pre
[index]
CSCI 2600 Spring 2021
 
Convert Spec to Formula, step 1:
absorb 
throws
 and 
returns
 into 
effects
26
Convert Spec to Formula, step 2: Convert
into Formula
set
 from 
java.util.ArrayList<T>
   
T set(int index, T element)
requires
: true
modifies
: this[index]
effects
:
 E =
 
if index < 0 || index ≥ size then 
             
  
throws IndexOutOfBoundsException 
                   else 
                      
 
this
post
[index] = element and returns this
pre
[index]
Denote 
effects
 expression by 
E
. Resulting formula is:
{
true
} 
code
 { 
(E ^
 (forall i ≠ index, this
post
[i] = this
pre
[i])) 
}
CSCI 2600 Spring 2021
27
Stronger Specification
CSCI 2600 Spring 2021
28
Stronger Specification
CSCI 2600 Spring 2021
29
Exercise
 
Convert 
PSoft
 spec into logical formula
public static int binarySearch(int[] a,int key)
  requires
: 
a
 is sorted in ascending order and a is non-null
  modifies:
 none
  
effects:
 none
  
returns:
 i such that a[i] = key if such an i exists; -1 otherwise
CSCI 2600 Spring 2021
30
 
effects:
 E: if key occurs in a then returns i such that a[i] = key else returns -1.
 
E more formally:
        E =
 
   
0 <= index => index < a.Length && a[index] = value
 
   ^ index < 0 ==> forall k :: 0 <= k < a.Length ==> a[k] != value
 
{ 
sorted(a) ^ a != null 
} 
code
 { 
E ^ (forall i :: 0 <= i < a.Length, a
pre
[i] = a
post
[i]) 
}
Exercise
 
static void listAdd2(List<Integer> lst1,
                     List<Integer> lst2)
  requires
:
 lst1
, 
lst2
 are non-null. 
lst1
 and 
lst2
 are same size.
  
modifies
: 
lst1
  
effects
: i-th element of 
lst1
 is replaced with the sum of
                i-th elements of 
lst1
 and 
lst2
  returns
: none
CSCI 2600 Spring 2021
31
 
{ 
(lst1 != null ^ lst2 != null ^ lst1.length = lst2.length)
 } 
code
 
{ 
(forall i :: 0 <= i < lst1.length => lst1
post
[i] = lst1
pre
[i] + lst2
pre
[i])
 
  ^ (forall i :: 0 <= i < lst2.length => lst2
post
[i] = lst2
pre
[i]) 
}
Exercise
 
private static void swap(int[] a, int i, int j)
requires
: 
a
 non-null, 
0<=i,j<a.length
modifies
: 
a[i]
 and 
a[j]
effects
: 
a
post
[i]=a
pre
[j]
 and 
a
post
[j]=a
pre
[i]
returns
: none
CSCI 2600 Spring 2021
static void swap(int[] a, int i, int j) {
 
int tmp = a[j];
     a[j] = a[i];
     a[i] = tmp;
}
32
 
{ 
R
 } 
code
 { 
( E ^ (forall k :: k != i,j a
post
[k] = a
pre
[k]) 
}
 
{ 
a != null ^ 0 <= i,j < a.length 
} 
code
{ 
(a
post
[i] = a
pre
[j] ^ a
post
[j] = a
pre
[i])
  ^ (forall k :: (0 <= k < a.length ^ k != i ^ k != j) 
==
>  a
post
[k] = a
pre
[k]) 
}
Comparison by Logical Formulas
We often use this equivalence direction:
If P
B
 => P
A
 and Q
A
 => Q
B 
then A is stronger than B
CSCI 2600 Spring 2021
33
Comparing Specifications, Review
It is not easy to compare specifications
Comparison by hand
Easier but can be imprecise
It may be difficult to see which of two conditions is stronger
Comparison by logical formulas
Accurate
Sometimes, it is difficult to express behaviors with precise logical formulas!
CSCI 2600 Spring 2021
34
Comparing by Hand
R
equires 
clause
Stronger spec
 has 
fewer
 conditions in requires
Requires less
Modifies/effects
 clause
Stronger spec
 modifies 
fewer
 objects. Stronger spec guarantees more objects
stay unmodified!
Returns 
and
 throws
 clauses
Stronger spec
 guarantees 
more
 in returns and throws clauses. They are
harder to implement, but easier to use by client
When pre-conditions are the same: no new throws in domain
When pre-conditions are weaker, it may guarantee more by specific throws.
(See e.g., Spec 
C
 of 
find
.)
Bottom line: Client code should not be “surprised” by behavior
CSCI 2600 Spring 2021
35
BallContainer and Box
Suppose 
Box
 is a subclass of 
BallContainer
Spec of BallContainer.add(Ball b)
boolean
 
add(Ball b)
requires
: 
b
 non-null
modifies
: 
this
 BallContainer 
effects
: adds 
b
 to this 
             BallContainer if 
b
 
             not already in
returns
: true if 
b
 is added
             false otherwise
Spec of Box.add(Ball b)
boolean
 
add(Ball b)
requires
: 
b
 non-null
modifies
: 
this
 Box 
effects
: adds 
b
 to this Box if 
b
 
            is not already in 
            
and Box is not full
returns
: true if 
b
 is added
            false otherwise
CSCI 2600 Spring 2021
36
BallContainer and Box
A client honoring BallContainer’s spec is justified to expect that this
will work:
BallContainer c = new Box(100);
for(int i = 0; i < 20; i++) {
 
Ball b = new Ball(10);
 
c.add(b)
}
This will fail, but if c is a BallContainer we expect it to work
Box’ spec 
is not stronger
 than BallContainer’s. Thus Box 
is not
substitutable
 for BallContainer!
Implementation that satisfies Box specs doesn't satisfy BallContainer
specs
CSCI 2600 Spring 2021
37
BallContainer and Box
BallContainer.add unconditionally adds the
Balls. Box has a condition --- the Box is not full.
Could a client coding against BallContainer
expect to work on Box?
Is Box guaranteeing more than BallContainer?
Box effects are weaker. Box’s effects guarantee
less.
BallContainer.add()
E = if b is_element BallContainer_pre
 
return false
      else
         BallContainer_post = BallContainer_pre U b
Box.add()
E 
= if b is_element BallContainer_pre
 
return false
      else
                if Box.volume_pre >= max_volume
                       return false
                else
 
     Box_post = Box_pre U b
Substitutability
Box is not what we call a 
true subtype 
of BallContainer
It is more limited than BallContainer.
A Box can only hold a limited amount;
A user who uses a BallContainer in their code cannot simply
substitute a BallContainer with a Box and assume the same
behavior in the program.
The code may cause the Box to fill up, but they did not have this
concern when using a BallContainer.
For this reason, it is not a good idea to make Box extend
BallContainer.
Therefore, it is 
wrong
 to make Box a subclass of
BallContainer
An object of a  true subtype should be able to do everything
the superclass object can do and possibly more
Substitutability
Box is not a 
true subtype
 (also called 
behavioral subtype
) of
BallContainer
Bottom line:
Box.add() guarantees less
Therefore, it is 
wrong
 to make Box a subclass of BallContainer
More on substitutability, Java subtypes and true subtypes later
CSCI 2600 Spring 2021
40
The Weakest Specification
requires: 
false
// Remember, 
false
 is the strongest condition of all
modifies:
 anything
effects: 
true
// 
true
 is the weakest condition of all
returns: 
true
 
throws: 
true
(This spec is so weak, it is trivial to implement, but impossible to use.)
CSCI 2600 Spring 2021
41
The Strongest Specification
requires: 
true
// Remember, 
true
 is the weakest condition of all
modifies:
 none
effects: 
false
// 
false
 is the strongest condition of all
returns: 
false
 
throws: 
false
(This spec is so strong, it is impossible to implement with a terminating
program.)
CSCI 2600 Spring 2021
42
Slide Note
Embed
Share

Specifications in software development play a crucial role in determining the strength of requirements and the ability to substitute implementations. This content discusses how stronger specifications imply weaker ones, the importance of satisfaction in specifications, and the application of the Liskov Substitution Principle to compare specification strength. It also outlines approaches for comparing specifications and provides an exercise highlighting differences between specifications A and B.

  • Software Development
  • Specification Strength
  • Substitutability
  • Liskov Substitution Principle

Uploaded on Oct 03, 2024 | 0 Views


Download Presentation

Please find below an Image/Link to download the presentation.

The content on the website is provided AS IS for your information and personal use only. It may not be sold, licensed, or shared on other websites without obtaining consent from the author. Download presentation by click this link. If you encounter any issues during the download, it is possible that the publisher has removed the file from their server.

E N D

Presentation Transcript


  1. Specifications, continued

  2. Review Spec A is stronger than B means For every implementation I Isatisfies A implies Isatisfies B If the implementation satisfies the stronger spec (A), it satisfies the weaker (B) The opposite is not necessarily true! For every client C C meets the obligations of B implies Cmeets the obligations of A If C meets the weaker spec (B), it meets the stronger spec (A) The opposite is not necessarily true A larger world of implementations satisfy the weaker spec B than the stronger spec A Consequently, it is easier to implement a weaker spec! Weaker specs require more AND/OR Weaker specs guarantee (promise) less CSCI 2600 Spring 2021 2

  3. Satisfaction of Specifications I is an implementation and S is a specification I satisfies S if Every behavior of I is permitted by S No behavior of I violates S The statement I is correct is meaningless, but often used If I does not satisfy S, either or both could be wrong I does something that S doesn t specify S expects a result that I doesn t produce When I doesn t satisfy S, it s usually better to change the program rather than the spec. If spec is too complex modify spec CSCI 2600 Spring 2021 3

  4. Why Compare Specs? Liskov Substitution Principle We want to use a subclass method in place of superclass method Spec of subclass method must be stronger Or at least equally strong Which spec is stronger? A procedure satisfying a stronger spec can be used anywhere a weaker spec is required. Does the implementation satisfy the specification? CSCI 2600 Spring 2021 4

  5. Comparing Specifications One way: by hand, examine each clause Another way: logical formulas representing the spec Use whichever is most convenient Comparing specs enables reasoning about substitutability CSCI 2600 Spring 2021 5

  6. Exercise Specification A: requires: a is non-null and value occurs in a modifies: none effects: none returns: the smallest index i such that a[i] = value Specification B: requires: a is non-null and value occurs in a // same as A modifies: none // same as A effects: none // same as A returns: i such that a[i] = value // fewer guarantees Therefore, A is stronger. In fact, A s postcondition implies B s postcondition CSCI 2600 Spring 2021 6

  7. Example Specification B: requires: a is non-null and value occurs in a modifies: none effects: none returns: i such that a[i] = value Specification A: requires: a is non-null // fewer conditions! modifies: none // same effects: none // same returns: i such that a[i] = value if value occurs in a and i = -1 if value is not in a // guarantees more! Therefore, A is stronger! CSCI 2600 Spring 2021 7

  8. Strong Versus Weak Specifications double sqrt(double x) A. @requires x>= 0 @return y such that |y^2 x| <= 1 B. @requires none @return y such that |y^2 x| <= 1 @throws IllegalArgumentException if x < 0 C. @requires x>= 0 @return y such that |y^2 x| <= 0.1 Which are stronger? CSCI 2600 Spring 2021 8

  9. Comparing Specifications Most of our specification comparisons will be informal A is stronger than B if A s precondition is weaker than B s (keeping postcondition the same) - Requires less of client Or A s postcondition is stronger than B s (keeping precondition the same) - Guarantees more to client Or A s precondition is weaker than B s AND A s postcondition is stronger than B s

  10. Comparing by Logical Formulas Specification S1 is stronger than S2 iff For all implementations I, (I satisfies S1) => (I satisfies S2) The set of implementations that satisfy S1 is a subset of the set of implementations satisfying S2. If each specification is a logical formula S1 => S2 Comparison using logical formulas is precise but can be difficult to carry out. It is often difficult to express all preconditions and postconditions with precise logical formulas! CSCI 2600 Spring 2021 10

  11. Implication Truth Table 11{ 1} { 1} { 1} { 1} { 1} S { 2} { 2} { 2} { 2} { 2} S { 1} S { 2} S S S CSCI 2600 Spring 2021 I I I I S S S I I I I S S S T F T T { 1} S I S 1 thesetof programssatisfying S implementationI isamemberof thesetof programssatisfying S S isasubsetof S { 1} S 1 { 1} { 2} S 1 2

  12. Comparing by Logical Formulas S1 is stronger than S2 (x is an element of set of programs satisfying S1) => (x is an element of the set of programs satisfying S2) the set of programs satisfying S1 is a subset of the set of programs satisfying S2 "A is a subset of B" if and only if every element of A also belongs to B An implementation I that satisfies S1 also satisfies S2 If (I satisfies S1) => (I satisfies S2) is false Then S1 does not imply S2, or S1 is not stronger than S2. If I does not satisfy S1, all bets are off. I might or might not satisfy S2. See http://press.princeton.edu/chapters/s8898.pdf CSCI 2600 Spring 2021

  13. Comparing by Logical Formulas Let Spec A: {PA} code {QA}, Spec B: {PB} code {QB}. We say code satisfies a specification with precondition P and postcondition Q iff {P} code {Q} Hoare triple is true. Do not confuse it with P => Q. e.g., { true } x = 1; { x = 1 } is true, but true => x = 1 is false. CSCI 2600 Spring 2021 13

  14. Comparing by Logical Formulas Let Spec A: {PA} code {QA}, Spec B: {PB} code {QB}. The following are equivalent: PB => PA and QA => QB A is stronger than B A => B CSCI 2600 Spring 2021 14

  15. Example Revisited: int find(int[] a, int val) int find(int[] a, int value) { for (int i=0; i<a.length; i++) { if (a[i] == value) return i; } return -1; } Specification B: requires: a is non-null and value occurs in a returns: i such that a[i] = value Specification A: requires: a is non-null returns: i such that a[i] = value or i = -1 if value is not in a

  16. Be careful with specifications! returns: i such that a[i] = value or i = -1 if value is not in a Let P = val occurs in a , Q = return i s.t. a[i] = val R = return -1 = = (P => Q) v (!P => R) (!P v Q) v (P v R) Q v R or would allow us to write a method that always returns -1!

  17. Be careful with specifications! returns: i such that a[i] = value or i = -1 if value is not in a We really mean: i such that a[i] = value if value is in a,ANDi = -1 if value is not in a . P => Q ^ !P => R is equivalent to: (P ^ Q) v (!P ^ R) v (Q ^ R) In our case, P => Q ^ !P => R and (P ^ Q) v (!P ^ R) are equivalent since Q^R is false (return -1 and return a value >= 0 cannot both be true.) So, we could also say: (i such that a[i] = value and value is in a) or (i = -1 and value is not in a) .

  18. Example: int find(int[] a, int val) Specification B: requires: a is non-null and val occurs in a[PB ] returns: i such that a[i] = val [QB ] Specification A: requires: a is non-null [PA ] returns: i such that a[i] = val if value val occurs in a and -1 if value val does not occur in a [QA ] Clearly, PB => PA. QA states val occurs in a => returns i such that a[i]=val AND val does not occur in a => returns -1 QBcan be logically rewritten as: val occurs in a => returns i such that a[i]=val AND val does not occur in a => returns anything. (violated precondition allows anything.) CSCI 2600 Spring 2021 18

  19. Comparing postconditions QB (postcondition of Spec B) i such that a[i] == value can be written (due to the precondition) as: value is in a => i such that a[i] == value && value is not in a => true QB and QA are NOT : QB2: {0 <= i < a.length} QA2: {-1 <= i < a.length} QA (postcondition of Spec A) value is in a => i such that a[i] == value && value is not in a => -1=i For these, QB2 => QA2, i.e., QB2 is stronger Which is stronger, QB or QA? CSCI 2600 Spring 2021 19

  20. Comparing by Logical Formulas Let A = {PA} code {QA}, B = {PB} code {QB} be Hoare triples. A is stronger than B if and only if PA is weaker than PB and QA is stronger than QB, i.e., A => B <==> (PB => PA ^ QA => QB). A => B means that any code satisfying A also satisfies B. CSCI 2600 Spring 2021 20

  21. Example: int find(int[] a, int val) Specification B: requires: a is non-null and val occurs in a[PB ] returns: i such that a[i] = val [QB ] Specification A: requires: a is non-null [PA ] returns: i such that a[i] = val if value val occurs in a and -1 if value val does not occur in a [QA ] PB requires more of the caller than PA. That is, PB => PA. QA promises more to the caller than QB (QB does not promise anything if val does not occur in a; e.g., code satisfying B could return -99.). That is, QA => QB. CSCI 2600 Spring 2021 21

  22. Example: int find(int[] a, int val) Specification B: requires: a is non-null and val occurs in a[PB ] returns: i such that a[i] = val [QB ] Specification A: requires: a is non-null [PA ] returns: i such that a[i] = val if val occurs in a and val does not occur in a [QA ] -1 if Intuition: QB should really be thought of as: i such that a[i] = val if val occurs in a Thus, it s still OK to substitute A for B. CSCI 2600 Spring 2021 22

  23. Exercise: int find(int[] a, int val) Sort specifications in order of strength Specification B: requires: a is non-null and val occurs in a[PB ] returns: i such that a[i] = val [QB ] Specification A: requires: a is non-null [PA ] returns: i such that a[i] = val if val occurs in a and val does not occur in a [QA ] Specification C: requires: none[PC ] returns: i such that a[i] = val if val occurs in a and val does not occur in a [QC ] throws: NullPointerException if a is null[QC ] -1 if -1 if CSCI 2600 Spring 2021 23

  24. Converting PSoft Specs into Logical Formulas PSoft specification requires: R modifies: M effects: E is equivalent to this logical formula {R} code {E ^ (nothing but M is modified)} throws and returns are absorbed into effects E CSCI 2600 Spring 2021 24

  25. Convert Spec to Formula, step 1: absorb throws and returns into effects PSoft specification convention requires: (unchanged) modifies: (unchanged) effects: returns: absorbed into effects throws: CSCI 2600 Spring 2021 25

  26. Convert Spec to Formula, step 1: absorb throws and returns into effects set method from java.util.ArrayList<T> T set(int index, T element) requires: true modifies: this[index] effects: thispost[index] = element throws: IndexOutOfBoundsException if index < 0 || index size returns: thispre[index] Absorb effects, returns and throws into new effects: E= if index < 0 || index size then throws IndexOutOfBoundsException else thispost[index] = element and returns thispre[index] CSCI 2600 Spring 2021 26

  27. Convert Spec to Formula, step 2: Convert into Formula set from java.util.ArrayList<T> T set(int index, T element) requires: true modifies: this[index] effects: E = if index < 0 || index size then throws IndexOutOfBoundsException else thispost[index] = element and returns thispre[index] Denote effects expression by E. Resulting formula is: {true} code { (E ^ (forall i index, thispost[i] = thispre[i])) } CSCI 2600 Spring 2021 27

  28. Stronger Specification S1 is stronger than S2 iff {R1} code {E1 ^ (only M1 is modified)} => {R2} code {E2 ^ (only M2 is modified)} iff R2 => R1 ^ (E1 ^ (only M1 is modified) => (E2 ^ (only M2 is modified)) if R2 => R1 ^ E1 => E2 ^ (only M1 is modified) => (only M2 is modified) iff R2 => R1 ^ E1 => E2 ^ (M1 M2) CSCI 2600 Spring 2021 28

  29. Stronger Specification S1 is stronger than S2 if R2 => R1 ^ E1 => E2 ^ (M1 M2) A stronger specification: Requires less Guarantees more Modifies less CSCI 2600 Spring 2021 29

  30. Exercise Convert PSoft spec into logical formula public static int binarySearch(int[] a,int key) requires: a is sorted in ascending order and a is non-null modifies: none effects: none returns: i such that a[i] = key if such an i exists; -1 otherwise effects: E: if key occurs in a then returns i such that a[i] = key else returns -1. E more formally: E = 0 <= index => index < a.Length && a[index] = value ^ index < 0 ==> forall k :: 0 <= k < a.Length ==> a[k] != value { sorted(a) ^ a != null } code { E ^ (forall i :: 0 <= i < a.Length, apre[i] = apost[i]) } CSCI 2600 Spring 2021 30

  31. Exercise static void listAdd2(List<Integer> lst1, List<Integer> lst2) requires: lst1, lst2 are non-null. lst1 and lst2 are same size. modifies: lst1 effects: i-th element of lst1 is replaced with the sum of i-th elements of lst1 and lst2 returns: none { (lst1 != null ^ lst2 != null ^ lst1.length = lst2.length) } code { (forall i :: 0 <= i < lst1.length => lst1post[i] = lst1pre[i] + lst2pre[i]) ^ (forall i :: 0 <= i < lst2.length => lst2post[i] = lst2pre[i]) } CSCI 2600 Spring 2021 31

  32. Exercise private static void swap(int[] a, int i, int j) requires: a non-null, 0<=i,j<a.length modifies: a[i] and a[j] effects: apost[i]=apre[j] and apost[j]=apre[i] returns: none static void swap(int[] a, int i, int j) { int tmp = a[j]; a[j] = a[i]; a[i] = tmp; } { R } code { ( E ^ (forall k :: k != i,j apost[k] = apre[k]) } { a != null ^ 0 <= i,j < a.length } code { (apost[i] = apre[j] ^ apost[j] = apre[i]) ^ (forall k :: (0 <= k < a.length ^ k != i ^ k != j) ==> apost[k] = apre[k]) } CSCI 2600 Spring 2021 32

  33. Comparison by Logical Formulas We often use this equivalence direction: If PB => PA and QA => QB then A is stronger than B CSCI 2600 Spring 2021 33

  34. Comparing Specifications, Review It is not easy to compare specifications Comparison by hand Easier but can be imprecise It may be difficult to see which of two conditions is stronger Comparison by logical formulas Accurate Sometimes, it is difficult to express behaviors with precise logical formulas! CSCI 2600 Spring 2021 34

  35. Comparing by Hand Requires clause Stronger spec has fewer conditions in requires Requires less Modifies/effects clause Stronger spec modifies fewer objects. Stronger spec guarantees more objects stay unmodified! Returns and throws clauses Stronger spec guarantees more in returns and throws clauses. They are harder to implement, but easier to use by client When pre-conditions are the same: no new throws in domain When pre-conditions are weaker, it may guarantee more by specific throws. (See e.g., Spec C of find.) Bottom line: Client code should not be surprised by behavior CSCI 2600 Spring 2021 35

  36. BallContainer and Box Suppose Box is a subclass of BallContainer Spec of BallContainer.add(Ball b) Spec of Box.add(Ball b) booleanadd(Ball b) booleanadd(Ball b) requires: b non-null modifies: this BallContainer effects: adds b to this BallContainer if b not already in returns: true if b is added false otherwise requires: b non-null modifies: this Box effects: adds b to this Box if b is not already in and Box is not full returns: true if b is added false otherwise CSCI 2600 Spring 2021 36

  37. BallContainer and Box A client honoring BallContainer s spec is justified to expect that this will work: BallContainer c = new Box(100); for(int i = 0; i < 20; i++) { Ball b = new Ball(10); c.add(b) } This will fail, but if c is a BallContainer we expect it to work Box spec is not stronger than BallContainer s. Thus Box is not substitutable for BallContainer! Implementation that satisfies Box specs doesn't satisfy BallContainer specs CSCI 2600 Spring 2021 37

  38. BallContainer and Box BallContainer.add unconditionally adds the Balls. Box has a condition --- the Box is not full. Could a client coding against BallContainer expect to work on Box? Is Box guaranteeing more than BallContainer? Box effects are weaker. Box s effects guarantee less. Box.add() E = if b is_element BallContainer_pre return false else if Box.volume_pre >= max_volume return false else Box_post = Box_pre U b BallContainer.add() E = if b is_element BallContainer_pre return false else BallContainer_post = BallContainer_pre U b

  39. Substitutability Box is not what we call a true subtype of BallContainer It is more limited than BallContainer. A Box can only hold a limited amount; A user who uses a BallContainer in their code cannot simply substitute a BallContainer with a Box and assume the same behavior in the program. The code may cause the Box to fill up, but they did not have this concern when using a BallContainer. For this reason, it is not a good idea to make Box extend BallContainer. Therefore, it is wrong to make Box a subclass of BallContainer An object of a true subtype should be able to do everything the superclass object can do and possibly more

  40. Substitutability Box is not a true subtype (also called behavioral subtype) of BallContainer Bottom line: Box.add() guarantees less Therefore, it is wrong to make Box a subclass of BallContainer More on substitutability, Java subtypes and true subtypes later CSCI 2600 Spring 2021 40

  41. The Weakest Specification requires: false // Remember, false is the strongest condition of all modifies: anything effects: true // true is the weakest condition of all returns: true throws: true (This spec is so weak, it is trivial to implement, but impossible to use.) CSCI 2600 Spring 2021 41

  42. The Strongest Specification requires: true // Remember, true is the weakest condition of all modifies: none effects: false // false is the strongest condition of all returns: false throws: false (This spec is so strong, it is impossible to implement with a terminating program.) CSCI 2600 Spring 2021 42

Related


More Related Content

giItT1WQy@!-/#giItT1WQy@!-/#giItT1WQy@!-/#giItT1WQy@!-/#giItT1WQy@!-/#giItT1WQy@!-/#giItT1WQy@!-/#giItT1WQy@!-/#giItT1WQy@!-/#giItT1WQy@!-/#