CS656/556 Notes on Assertions
Assertions have been a part of prgramming since the time of Von Neuman. This document discribes the various types.
At first assertions appeared as annotations or comments added to the design for a program. These designs where expressed as flowcharts. The annotaions where statements that would be true any time the program went through them. In 1967 Robert W Floyd named them invariants and showed how they could provide semantics to a flowchart ( "Assigning Meaning to Programs", pp19-32 of Proceedings of Symposia in Applied Mathematics Vol XIX ). Donald Knuth used them in his monumental "Art of Computer Programming". These assertions were logical statements attached to a point in a program. They were used by programmers trying to write and/or understand the code. We used them to check that the code worked. Typically, there was one for each branch and loop in a program. I used theme for key parts of my Ph. D. work. They made sure that no bugs were ever found in the key parts of the program (bugs appeared where I didn't use assertions).
With the development of modular programs and high level languages we learned to document pre-conditions and post-conditions for each subprogram. A pre-condition is written at the start of a subprogram. It states the conditions that can be assumed by the subprogram when it starts. Pre-conditions are to be set up by the clients of the subprogram. For example the pre-condition for a square root routine is that the argument is not negative. A post-condition states what is going to be true when the subprogram exits. Conceptually they belong at the end the code.
Programmers also got into the habit of coding executable assertions. An executable assertion does nothing if the condition was true. If it is false, the program halts and an error message is displayed -- this must state which subprogram has the problem and the condition that is broken. I used this style in a successful team project in the early 1970s. Pre and post conditions are now a part of object-oriented programming and the UML. They can be used to document functions so that they can be used without studying the code inside. In the following "i0" stands for the value of i when the function is called. This allows the value of i to change as the function is executed.
int isqrt(int i);
// pre: i == i0 and i0 >=0
// post: n is returned where n*n <= i0 <(n+1)*(n+1)
When C was created, a special library <assert.h> was developed that supported executable assertions. See the manual on the other side of this piece of paper. Here is an executable C/C++ pre-condition:
int isqrt(int i)
{ assert( i >=0 ));
A pre+post-condition pair is now called a contract. They are the heart of a programming method and language developed by Bertrand Meyer (Object-Oriented software construction, Prentice Hall QA76.6 M4845 1988, pages 111..128). He also reintroduced the idea of an invariant at the class level. A class invariant is a property of objects of a given class. Whenever no function is executing the invariant is true. Proving it true is not difficult: just show that every constructor and every method guarantees that the invariant is still true. Then, the code in each method can assume that the invariant is true.
Recently, executable assertions have been given a new use in extreme programming. This is as unit tests. A unit test tests to see if a module is working correctly. They are written outside the code being tested. In extreme programming you always write a set of test cases first and then start working to make the code pass the tests.
for ( i = 0; i<30; i++)
{ n = isqrt(i);
assert( (n*n <= i) && (i < (n+1)*(n+1)));
}
More Reading
WikiWikiWiki
http://c2.com/cgi/wiki?WhatAreAssertions
http://c2.com/cgi/wiki?UnitTests
http://c2.com/cgi/wiki?DesignByContract
Facsimile Manual Page for assert is over the page
ASSERT(3) Linux Programmer's Manual ASSERT(3)
NAME
assert - Abort the program if assertion is false.
SYNOPSIS
#include <assert.h> (in C)
#include <cassert> (in C++)
void assert (int expression);
DESCRIPTION
assert() prints an error message to standard output and
terminates the program by calling abort() if expression is
false (i.e., compares equal to zero). This only happens
when the macro NDEBUG was undefined when <assert.h> was
last included.
RETURN VALUE
No value is returned.
CONFORMING TO
ISO9899 (ANSI C). In the 1990 standard, expression is
required to be of type int and undefined behavior results
if it is not, but in the 1999 standard it may have any
scalar type.
BUGS
assert() is implemented as a macro; if the expression
tested has side - effects, program behaviour will be dif-
ferent depending on whether NDEBUG is defined. This may
create Heisenbugs which go away when debugging is turned
on.
SEE ALSO
exit(3), abort(3)
GNU April 4, 1993 ASSERT(3)