Plain Text Specification Notation

H. Conrad Cunningham

22 April 2022

Copyright (C) 2022, H. Conrad Cunningham
Professor of Computer and Information Science
University of Mississippi
214 Weir Hall
P.O. Box 1848
University, MS 38677
(662) 915-7396 (dept. office)

Browser Advisory: The HTML version of this textbook requires a browser that supports the display of MathML. A good choice as of April 2022 is a recent version of Firefox from Mozilla.

1 Plain Text Specification Notation

1.1 Chapter Introduction

This chapter informally defines the mathematical and logical notation we use to express the semantics of program units such as functions, procedures, methods, modules, and classes. We use it to specify abstract models, invariants, preconditions, and postconditions.

We adopt a plain-text notation that can be typed as comments in program source code, not the notation that would be typeset in a mathematics or logic textbook. The logic notation follows that popularized by David Gries [9,10], Edsger Dijkstra [7,8], and others [3–5,12,14] in the formal methods community.

We assume that the readers of our specifications are familiar with basic mathematical concepts such as logical connectives, sets, relations, functions, etc. The primary purpose of this chaper is to introduce the plain-text notation.

1.2 Program States and Specification

The state of a program is a mapping of all the variables to their respective values. Here we use the term “variable” flexibly to enable this notation to be used for a variety of languages and circumstances. It includes all the program’s named constants, variables, parameters, and types and perhaps other entities such as the program counter(s), input/output channels, and program metadata.

A state space for a program is the set of all possible states.

If E is an expression defined in some state space, x is a variable, and v is a possible value for that variable, then the notation E(x := v) denotes the expression E where all occurrences of the variable x are replaced by the value v. Similarly, the notation E(x,y := u,v) denotes the expression E where all occurrences of the variables x and y are simultaneously replaced by the values u and v, respectively.

To evaluate an expression in a state means to replace all the variables in the expression by their respective values in that state and then compute the resulting value.

In specifying computer programs, we use predicates (i.e., logical expressions) to assert that a condition must hold at all points in the program’s state space.

Consider a function in a programming language. The functions precondition predicate asserts what must be true about the program’s state and the values of the function’s arguments at a program location where the function is called. Note that a precondition implicitly includes an assertion about value of the program counter. Similarly, the function’s postcondition predicate asserts what must be true about the program’s state and the function’s return value at a program location where the function returns.

1.3 Predicate Logic

A predicate is an expression that evaluates to either the Boolean value true or the Boolean value false at a point in the state space in which predicate is well-defined. In the following, we informally describe the syntax and semantics of predicates.

1.4 Other Quantifications

In addition to the logical quantification above, we can also use quantified expressions that involve other operators and yield other types of values (e.g., integers).

If OP is a binary operator on some type that is associative and commutative (or symmetric) and has an identity element, then we can readily define a quantification (OP x : R :: T) [10].

To evaluate the quantification (OP x : R :: T), we:

  1. generate a “list” containing the values of term expression T(x := v) for each value v of the dummy variable x that satisfies the range predicate R(x := v)

  2. insert the associative and commutative binary operator op between adjacent elements of the list

  3. compute the value of the generated expression

If the range is empty (i.e., there are no values of x for which Ris true), then the value of the quantification is the identity element for binary operator OP.

Thus, in addition to universal and existential quantification discussed in the previous section, we can define the following common arithmetic quantifications according to above general rules:

In addition, we can define numerical quantification expressions as follows:

Consider the binary operators min and max. They are associative and commutative.

On the one hand, if we consider any set of values that is bounded above by a maximum value, then the maximum value is the identity element for the min operation on that set. Similarly, if we consider any set of values that is bounded below by a minimum value, then the minimum value is the identity element for the max operation on that set.

On the other hand, if we consider any set of values that is unbounded above (e.g., the positive integers), then min does not have an identity element within the set. Similarly, if we consider any set of values that is unbounded below (e.g., the negative integers), then max does not have an identity element within the set. We could, however, assign some special values such as ++\infty as the identity element for min and -\infty as the identity element for max.

Thus, we can define two other useful quantifications:

Note: Given that it may be impossible to represent POS_INF and NEG_INF in a program, in most circumstances it is best to avoid use of minimimization and maximization in specifying computer programs.

1.5 Sets

A set is an unordered collection of elements without duplicates.

1.6 Relations

1.7 Bags

Mathematically, a bag (or multiset) is a function from some arbitrary set of elements (the domain) to the set of nonnegative integers (the range) [10:11.7,15,16]. We interpret the nonnegative integer as the number of occurrences of the element in the bag. Zero means the element does not occur. The number of occurrences of an element in a bag is also called its multiplicity.

From another perspective, a bag is an unordered collection of elements. Each element may occur one or more times in the bag. (It is like a set except values can occur multiple times.)

OCCURRENCES(1,{| 1, 1, 2, 1 |}) = 3
OCCURRENCES(3,{| 1, 1, 2, 1 }}) = 0

CARD({| 1, 1, 2, 1 |}) = 4
CARD({| |) = 0

1.8 Sequences

TODO

1.9 What Next?

This document defines the plain-text notation we use to specify the semantics of programs. Source code comments and other documents can refer to this chapter rather than describe the notation used.

1.10 Acknowledgements

In the early 1990s, I wrote A Programmer’s Introduction to Predicate Logic [4] as a supplement for my students in the CSci 550 (Program Semantics and Derivation) [5] and Engr 664 (Theory of Concurrent Programming) courses. For CSci 555, I used the textbooks by Gries [9] and Cohen [3] and gradually developed my own set of mostly compatible notes [4,5]. My use of predicate logic and equational reasoning was also influenced by Jan Tijmen Udding from whom I took my first course on program derivation in the 1980s, my dissertation advisor Gruia-Catalin Roman, Dijkstra [7,8], Gries’s discrete mathematics textbook [10], and other sources [1,2,11,12,14].

In Fall 1996, I began teaching courses on object-oriented programming and software architecture. For those courses, I informally used approaches such as constructive semantics for abstract data types (e.g., as described in my notes on Data Abstraction [6]) and Meyer’s design-by-contract [13]. I also developed example programs written in various languages (e.g., Java, Ruby, Scala, Lua, Elixir, and Python and annotated the programs with comments giving preconditions, postconditions, and invariants, usually without much explanation of the specification notation I was using. Over the years, I wrote a number of partial and often incompatible explanations of the notation.

I retired from the full-time faculty in May 2019. As one of my post-retirement projects, I am continuing work on possible textbooks based on the course materials I had developed during my three decades as a faculty member. In January 2022, I began refining the existing content, integrating separately developed materials together, reformatting the documents, constructing a unified bibliography (e.g., using citeproc), and improving my build workflow and use of Pandoc.

I wrote this document in 2022 to unify the description of the notation I have used in mt example programs (e.g., the CookieJar, CandyBowl, and Digraph ADTs) and other documents.

I maintain this chapter as text in Pandoc’s dialect of Markdown using embedded LaTeX markup for the mathematical formulas and then translate the document to HTML, PDF, and other forms as needed.

1.11 References

[1]
Richard Bird and Philip Wadler. 1988. Introduction to functional programming (First ed.). Prentice Hall, Englewood Cliffs, New Jersey, USA.
[2]
K. Mani Chandy and Jayadev Misra. 1988. Parallel program design: A foundation. Addison-Wesley, Boston, Massachusetts, USA.
[3]
Edward Cohen. 1990. Programming in the 1990’s: An introduction to the calculation of programs. Springer, New York, New York, USA.
[4]
H. Conrad Cunningham. 2006. A programmer’s introduction to predicate logic. University of Mississippi, Department of Computer and Information Science, University, Mississippi, USA. Retrieved from https://john.cs.olemiss.edu/~hcc/docs/PredicateLogicNotes/Programmers_Introduction_to_Predicate-Logic.pdf
[5]
H. Conrad Cunningham. 2006. Notes on program semantics and derivation. University of Mississippi, Department of Computer and Information Science, University, Mississippi, USA. Retrieved from https://john.cs.olemiss.edu/~hcc/reports/umcis-1994-02.pdf
[6]
H. Conrad Cunningham. 2019. Notes on data abstraction. University of Mississippi, Department of Computer and Information Science, University, Mississippi, USA. Retrieved from https://john.cs.olemiss.edu/~hcc/docs/DataAbstraction/DataAbstraction.html
[7]
Edsger W. Dijkstra and Wim H. J. Feijen. 1988. A method of programming. Addison-Wesley, Boston Massachusetts, USA.
[8]
Edsger W. Dijkstra and Carel S. Scholten. 1990. Predicate calculus and program semantics. Springer, New York, New York, USA.
[9]
David Gries. 1981. Science of programming. Springer, New York, New York, USA.
[10]
David Gries and Fred B. Schneider. 1993. A logical approach to discrete math. Springer, New York, New York, USA.
[11]
Robert R. Hoogerwoord. 1989. The design of functional programs: A calculational approach. PhD thesis. Eindhoven Technical University, Eindhoven, The Netherlands.
[12]
Anne Kaldewaij. 1990. Programming: The derivation of algorithms. Prentice Hall, New York, New York, USA.
[13]
Bertrand Meyer. 1997. Object-oriented program construction (Second ed.). Prentice Hall, Englewood Cliffs, New Jersey, USA.
[14]
Antonetta J. M. van Gasteren. 1990. On the shape of mathematical arguments. Springer, Berlin, Germany.
[15]
Wikpedia: The Free Encyclopedia. 2022. Multiset. Retrieved from https://en.wikipedia.org/wiki/Multiset
[16]
Wolfram Research, Inc. 2022. Multiset. Retrieved from https://mathworld.wolfram.com/Multiset.html