Chapter 3 — Logic and specifications¶
Specifications are written in logic: formulas built from comparisons, Boolean connectives, and quantifiers. The patterns below recur throughout the rest of the book.
Predicates and states¶
A predicate is a formula that can be true or false depending on variable values.
A program state assigns values to variables (x = 3, y = -1, …).
Example predicates about integers x and y:
x >= 0
x < y
x >= 0 && y >= 0 // conjunction (AND)
x == 0 || y == 0 // disjunction (OR)
!(x == y) // negation (NOT)
Implication — the heart of contracts¶
Implication \(P \Rightarrow Q\) reads “if P then Q.”
When
Pis false, the implication is vacuously true (we make no promise in impossible worlds).When
Pis true,Qmust hold.
Function contracts will have the shape:
precondition P ==> (code ensures) postcondition Q
Equivalently: every call that satisfies P must leave the world satisfying Q (if the call terminates).
Quantifiers (preview)¶
To say “every element of the array is non-negative”:
forall i in [0, n) . arr[i] >= 0
To say “there exists an index with value target”:
exists i in [0, n) . arr[i] == target
CppVerify uses bounded forall / exists syntax in contracts; the idea is standard first-order logic
over integers and arrays.
Abstraction in specifications¶
Good specifications are stable under implementation changes:
Too concrete |
Better |
|---|---|
|
|
“uses a while loop” |
“returns the sum of 0..n” |
Abstract specs let you replace algorithms without changing callers’ proofs.