Vous êtes sur la page 1sur 24

What, When, How

Programs vs. Specifications

COMP2111 Lecture 1
Session 1, 2017

Kai Engelhardt

Revision: 1.3


Put the word engineering back into SE.

In marginally more detail (= Immd): climb up the ladder of
1 Craft code that (provably) works according to specifications.
2 Cobble together code that passes a few tests.
3 Crap out code so it beats the compiler’s checks.


All of it, and in this one session.

Immd: we shall be spending time on
acquiring and understanding languages to specify systems
(both fully formal and informal ones)
using such languages to specify some simple systems or tasks,
clearly and concisely
developing notions of refinement between artifacts in said
languages to guide a systematic code/system development
using refinement to derive correct-by-construction, beautiful
code from concise and clear specifications


We’ll use light-weight informal methods to foster

We’ll investigate the mathematical underpinnings of both:
1 What’s in a spec?
2 What’s in a program?
3 And: How do we get from the former to the latter?

Top-Down Program Construction: an Example #1

Reminder: facts about the factorial function ! : N −→ N are:

0! = 1 (fac1)
(n + 1)! = (n + 1) · n! (fac2)

(fac1) tells us what the factorial of 0 is while (fac2) shows how to

find the factorial of a number if we know the factorial of its
Together they’re also know as an inductive definition of the
(mathematical) factorial function.

Top-Down Program Construction: an Example #2

Task: Given a number n ∈ N, we want to compute its factorial n!

without changing n in the process.
1 Use (fac1) to compute 0!.
2 Repeatedly use (fac2) to compute factorials of larger numbers
Who said COMP2111 was going to be difficult?!?

Interlude: we could be done already. . .

. . . if we used Haskell in first year. You’ll meet it in COMP3141.

fact :: Integer −> Integer
fact 0 = 1
fact n = n ∗ fact (n−1)

but we’re using C.

TODO: insert million flies argument

unsigned int fact(unsigned int n) {
return (n == 0) ? 1 : n ∗ fact (n−1);

this works for a few values

Top-Down Program Construction: an Example #3

Recursion is cool but what if we want an iterative solution?

We could use a variable f to save the last factorial we have
computed, and an additional variable k to keep track of the number
such that f = k!. Now we can adapt the plan to
1 Achieve f = k! by setting k to 0 and f to 1.
2 As long as k 6= n, increase k and change f in a way that
preserves f = k!.
In C, with comments for pseudo-code
k = 0; f = 1;
while (k != n) {
/∗ increase k and change f while maintaining f = k! ∗/

Top-Down Program Construction: an Example #4

f = k! is called a loop invariant. Of course, loop bodies are

supposed to change the state, but invariants express properties of
the state that are preserved by executing the loop body.
Invariants are crucial ingredients of correctness proofs, but they do
not address termination.
To argue termination of a loop (or recursion) we use variants, i.e.,
functions that map program states to N (or any other well-founded
domain in general). To show that a loop terminates, one proves that
every iteration of the body strictly decreases the value of the variant.
A suitable variant here would be n − k because
/∗ increase k and blah ∗/

decreases the value of n − k by some v > 0.

Top-Down Program Construction: an Example #5
It remains to implement
/∗ increase k and change f while maintaining f = k! ∗/

We decide to change k first

k = k+1; /∗ change f to re−establish f = k! ∗/

Observe that the invariant won’t hold after the increment, but
instead f = (k − 1)! is true.
k = k+1; /∗ assuming f = (k−1)!,
change f to establish f = k! ∗/

(fac2) suggests the implementation

f = k∗f

Top-Down Program Construction: an Example #6

One popular formal notation for pseudo-code specifications such as

/∗ assuming f = (k−1)!, change f to establish f = k! ∗/

is Carroll Morgan’s specification statement

f : [f = (k − 1)!, f = k!]

which expresses that, if the initial state satisfies the precondition

f = (k − 1)! then change only the variables listed in the frame f so
that the resulting final state satisfies the postcondition, f = k!.
(See his book Programming from Specifications.)


We’ve followed a simple recipe

1 Take an unwritten portion of the program whose purpose is
precisely and completely specified.
2 Replace this portion by a statement which may in turn contain
portions that are unwritten but precisely and completely
3 Prove (or at least convince yourself) that the new statement
will meet its specification if its unwritten portions meet their
4 Repeat the above process until the entire program is written.
Taken almost verbatim from John C Reynolds’ book [Rey81], following
Niklaus Wirth’s program development by stepwise refinement [Wir71].

Reflection cont’d

We haven’t accomplished anything we couldn’t do before, but that

wasn’t really the point.
We have alluded to concepts such as
What do they really mean?
Carroll’s book [Mor90] answers these questions. And so do many
other books.

Connection to Year 1

Besides the (obvious?) relation to previous SE workshops, there’s a

fundamental connection to COMP1927.
Essentially, COMP1927 was about data structures + operations on
Our first example is a degenerate one in that respect: the data
structure is a single natural number and the only operation
computes the factorial of that number. In contrast to COMP1927,
we elicited a formal specification of that operation, namely

f : [n ∈ N, f = n!]

In COMP1927 you’d instead read an informal requirement such as
“the data structure represents a directed graph (V , E ) and
a desirable operation would tell you whether there is a
path between two given vertices x and y ”
Since, in a galaxy far across the universe we’ve already met
predicate logic and the specification statement, we could formalise
that the “desirable operation” stores its result in b by
∃n ∈ N, f : 0..n −→ V .f (0) = x ∧ f (n) = y ∧
b : x, y ∈ V , b ≡
∀i ∈ 1..n.(f (i − 1), f (i)) ∈ E

Yes, that means you do need your little bit of predicate logic in this

Specification Statement (revisited)

One popular formal notation for pseudo-code specifications such as

/∗ assuming A, change x to establish B ∗/

is Carroll Morgan’s specification statement [Mor90]

x : [A, B]

which expresses that, if the initial state satisfies the precondition A

then change only the variables listed in the frame x so that the
resulting final state satisfies the postcondition, B.

General Setting (13s1 and before)

Some variables representing our abstract data.

Perhaps some sanity conditions, or data invariants, on the data
An initialisation of the variables that establishes the invariants.
A set operations, each of which maintains the data invariants.
This is the (e.g.) Event-B view of all problems, closely related to
the COMP1927 view of data structures + operations.

General Setting (14s1 and after)

Some variables representing our data, including inputs and outputs.

A description of the desired relationship between input values and
output values.
This is the “programming from specifications” view of problems,
closely related to the COMP1917 view of programming tasks. We’ll
take this view for most of the session.
Much more motivation ⇐ SENG2011.

To give proper meaning to all the bits, the various existing methods
use one or more of
an article or book describing the formal semantics of assertions,
specifications, programs etc
a software tool implementing a particular semantics of said
In theory, if both are provided, they coincide.
In practice, they hardly ever do.
If none or only the second is provided, avoid: amateur alert.
Event-B + Rodin are in the good books: they have published formal
semantics for the language and the tool appears to implement
(most of) it.

What next

Register for our forum.

Find an assignment partner (anyone also in COMP2111).
Read chapters 1 and 3 of [LLM17].
Check out Carroll’s book. It’s free and a good read, avoiding
semantic shenanigans for all but one rather remote chapter. If
you feel more ambitious, check out Reynolds’ book. It’s also
free but at your (average) level of mathematical maturity, it
could be challenging.
Questions =⇒ our COMP2111 forums

Where can I practice my programming?

Read code daily.

Write code daily.
Follow discussions on stackoverflow or play some code golf.
Take an interest in any (open source?) coding project.

Where can I refresh my discrete maths?

Same advice: read. . . , write. . . , etc. If you don’t use your maths
then your brain is going to rot.
Succeeding in COMP2111 requires a modest amount of
mathematical maturity. Rather than pointing to your MATH1081
course notes, I recommend [LLM17], some 900+ page unfinished
textbook available online. Not every chapter is equivally relevant to
this course but most are relevant to CS one way or the other. Most
importantly, it’s a good read!

Eric Lehman, F. Thomson Leighton, and Albert R. Meyer.
Mathematics for computer science.
Available at https:
check https://courses.csail.mit.edu/6.042 for newer
versions, 2017.
Carroll C. Morgan.
Programming from Specifications.
Prentice Hall, 1990.
Available at http://www.cse.unsw.edu.au/~carrollm/
John C. Reynolds.
The Craft of Programming.
Prentice Hall, 1981.
Out of print. Reproductions are available at
Niklaus Wirth.
Program development by stepwise refinement.
Communications of the ACM, 14:221–227, 1971.