VDM Manual
VDM Manual
VDMTools
The VDM++ Language
CSK
How to contact CSK:
Contents
1 Introduction 1
1.1 Purpose of The Document . . . . . . . . . . . . . . . . . . . 1
1.2 History of The Language . . . . . . . . . . . . . . . . . . . . 1
1.3 Structure of the Document . . . . . . . . . . . . . . . . . . . 2
2 Conformance Issues 2
5 Algorithm Definitions 32
6 Function Definitions 33
6.1 Polymorphic Functions . . . . . . . . . . . . . . . . . . . . . 37
6.2 Higher Order Functions . . . . . . . . . . . . . . . . . . . . . 38
7 Expressions 39
7.1 Let Expressions . . . . . . . . . . . . . . . . . . . . . . . . . 39
7.2 The Define Expression . . . . . . . . . . . . . . . . . . . . . . 42
7.3 Unary and Binary Expressions . . . . . . . . . . . . . . . . . 44
7.4 Conditional Expressions . . . . . . . . . . . . . . . . . . . . . 45
7.5 Quantified Expressions . . . . . . . . . . . . . . . . . . . . . 47
7.6 The Iota Expression . . . . . . . . . . . . . . . . . . . . . . . 49
i
The VDM++ Language
8 Patterns 71
9 Bindings 76
11 Instance Variables 78
12 Operation Definitions 80
12.1 Constructors . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
13 Statements 84
13.1 Let Statements . . . . . . . . . . . . . . . . . . . . . . . . . . 84
13.2 The Define Statement . . . . . . . . . . . . . . . . . . . . . . 86
13.3 The Block Statement . . . . . . . . . . . . . . . . . . . . . . 88
13.4 The Assignment Statement . . . . . . . . . . . . . . . . . . . 89
13.5 Conditional Statements . . . . . . . . . . . . . . . . . . . . . 92
13.6 For-Loop Statements . . . . . . . . . . . . . . . . . . . . . . 94
13.7 The While-Loop Statement . . . . . . . . . . . . . . . . . . . 96
13.8 The Nondeterministic Statement . . . . . . . . . . . . . . . . 97
13.9 The Call Statement . . . . . . . . . . . . . . . . . . . . . . . 99
13.10 The Return Statement . . . . . . . . . . . . . . . . . . . . . 101
ii
The VDM++ Language
16 Threads 127
16.1 Periodic Thread Definitions . . . . . . . . . . . . . . . . . . . 127
16.2 Procedural Thread Definitions . . . . . . . . . . . . . . . . . 129
iii
The VDM++ Language
iv
The VDM++ Language
Index 178
v
The VDM++ Language
vi
The VDM++ Language
1 Introduction
This document is the language reference manual for VDM++. The syntax of
VDM++ language constructs is defined using grammar rules. The meaning of
each language construct is explained in an informal manner and some small ex-
amples are given. The description is supposed to be suited for ‘looking up’ infor-
mation rather than for ‘sequential reading’; it is a manual rather than a tutorial.
The reader is expected be familiar with the concepts of object oriented program-
ming/design.
We will use the ASCII (also called the interchange) concrete syntax but we will
display all reserved words in a special keyword font. This is done because the
document works as a language manual to the VDM++ Toolbox where the ASCII
notation is used as input. The mathematical concrete syntax can be generated
automatically by the Toolbox so a nicer looking syntax can be produced.
VDM++ has been under development since 1992; see [3] for its original de-
scription. Since then, the language has been further developed as part of the
AFRODITE1 project. VDM++ is based on the development in the AFRODITE
project. In the process of language development, feedback and evaluation of the
language from a number of larger case studies has been used.
The VDM++ language is the language supported by the VDM++ Toolbox. This
Toolbox contains a syntax checker, a static semantics checker, an interpreter2 , a
code generator to C++, and a UML link. Because ISO/VDM-SL in general is a
1
AFRODITE has been sponsored by the European Union under the ESPRIT programme
(EP6500).
2
In addition the Toolbox provides pretty printing facilities, debugging facilities and support
for test coverage, but these are the basic components.
1
The VDM++ Language
Section 2 indicates how the language presented here and the corresponding VDM++
Toolbox conform to the VDM-SL standard. Section 3 presents the BNF nota-
tion used for the description of syntactic constructs. The VDM++ notation is
described in section 4 to section 16. Section 17 provides a complete list of the
differences between ISO/VDM-SL and VDM++ while section 18 contains a short
explanation of the static semantics of VDM++. The complete syntax of the lan-
guage is described in Appendix A, the lexical specification in Appendix B and the
operator precedence in Appendix C. Appendix D presents a list of the differences
between symbols in the mathematical syntax and the ASCII concrete syntax. In
Appendex E details of the Standard library and how to use it are given. Finally,
an index of the defining occurrences of all the syntax rules in the document is
given.
2 Conformance Issues
The VDM-SL standard has a conformance clause which specifies a number of lev-
els of conformity. The lowest level of conformity deals with syntax conformance.
The VDM++ Toolbox accepts specifications which follow the syntax description
in the standard with the exceptions described in section 17.
Level one in the conformance clause deals with the static semantics for possible
correctness (see section 18). In this part we have chosen to reject more specifica-
tions than the standard prescribes as being possibly well-formed3 .
3
For example with a set comprehension where a predicate is present the standard does not
check the element expression at all (in the possibly well-formedness check) because the predicate
could yield false (and thus the whole expression would just be another way to write an empty
set). We believe that a user will be interested in getting such parts tested as well.
2
The VDM++ Language
Level two and the following levels (except the last one) deal with the definite
well-formedness static semantics check and a number of possible extended checks
which can be added to the static semantics. The definitely well-formedness check
is present in the Toolbox. However, we do not consider it to be of major value
for real examples because almost no “real” specifications will be able to pass this
test.
The last conformance level deals with the dynamic semantics. Here it is required
that an accompanying document provides details about the deviations from the
standard dynamic semantics (which is not executable). This is actually done in
this document by explaining which constructs can be interpreted by the Toolbox
and what the deviations are for a few constructs. Thus, this level of conformance
is satisfied by the VDM++ Toolbox.
To sum up, we can say that VDM++ (and its supporting Toolbox) is quite close
conforming to the standard, but we have not yet invested the time in ensuring
this.
Wherever the syntax for parts of the language is presented in the document it
will be described in a BNF dialect. The BNF notation used employs the following
special symbols:
, the concatenate symbol
= the define symbol
| the definition separator symbol (alternatives)
[ ] enclose optional syntactic items
{ } enclose syntactic items which may occur zero or more
times
‘ ’ single quotes are used to enclose terminal symbols
meta identifier non-terminal symbols are written in lower-case letters
(possibly including spaces)
; terminator symbol to denote the end of a rule
() used for grouping, e.g. “a, (b | c)” is equivalent to “a, b
| a, c”.
– denotes subtraction from a set of terminal symbols (e.g.
“character – (‘"’)” denotes all characters excepting the
double quote character.)
3
The VDM++ Language
Amount = nat
Here we have defined a data type with the name “Amount” and stated that the
values which belong to this type are natural numbers (nat is one of the basic
types described below). One general point about the type system of VDM++
which is worth mentioning at this point is that equality and inequality can be
used between any value. In programming languages it is often required that
the operands have the same type. Because of a construct called a union type
(described below) this is not the case for VDM++.
In this section we will present the syntax of data type definitions. In addition,
we will show how values belonging to a type can be constructed and manipulated
(by means of built-in operators). We will present the basic data types first and
then we will proceed with the compound types.
In the following a number of basic types will be presented. Each of them will
contain:
4
The VDM++ Language
For each of the built-in operators the name, the symbol used and the type of
the operator will be given together with a description of its semantics (except
that the semantics of Equality and Inequality is not described, since it follows
the usual semantics). In the semantics description identifiers refer to those used
in the corresponding definition of operator type, e.g. a, b, x, y etc.
The basic types are the types defined by the language with distinct values that
cannot be analysed into simpler values. There are five fundamental basic types:
booleans, numeric types, characters, tokens and quote types. The basic types
will be explained one by one in the following.
Name: Boolean
Symbol: bool
Operators: Assume that a and b in the following denote arbitrary boolean ex-
pressions:
Operator Name Type
not b Negation bool → bool
a and b Conjunction bool ∗ bool → bool
a or b Disjunction bool ∗ bool → bool
a => b Implication bool ∗ bool → bool
a <=> b Biimplication bool ∗ bool → bool
a = b Equality bool ∗ bool → bool
a <> b Inequality bool ∗ bool → bool
5
The VDM++ Language
6
The VDM++ Language
not a ≡ false
a and b ≡ false
b and ⊥ ≡ false
a or b ≡ true
a or ⊥ ≡ true
a => b ≡ false
b => b ≡ true
b => ⊥ ≡ true
a <=> b ≡ false
a = b ≡ false
a <> b ≡ true
⊥ or not ⊥ ≡ ⊥
(b and ⊥) or (⊥ and false) ≡ ⊥
There are five basic numeric types: positive naturals, naturals, integers, rationals
and reals. Except for three, all the numerical operators can have mixed operands
of the three types. The exceptions are integer division, modulo and the remainder
operation.
The five numeric types denote a hierarchy where real is the most general type
followed by rat6 , int, nat and nat1.
Type Values
nat1 1, 2, 3, ...
nat 0, 1, 2, ...
int ..., -2, -1, 0, 1, ...
real ..., -12.78356, ..., 0, ..., 3, ..., 1726.34, ...
This means that any number of type int is also automatically of type real but not
necessarily of type nat. Another way to illustrate this is to say that the positive
natural numbers are a subset of the natural numbers which again are a subset of
the integers which again are a subset of the rational numbers which finally are a
subset of the real numbers. The following table shows some numbers and their
associated type:
6
From the VDM++ Toolbox’s point of view there is no difference between real and rat
because only rational numbers can be represented in a computer.
7
The VDM++ Language
Number Type
3 real, rat, int, nat, nat1
3.0 real, rat, int, nat, nat1
0 real, rat, int, nat
-1 real, rat, int
3.1415 real, rat
Note that all numbers are necessarily of type real (and rat).
8
The VDM++ Language
Note that the order of floor and abs on the right-hand side makes a differ-
ence, the above example would yield -5 if we changed the order. This is
because floor always yields a smaller (or equal) integer, e.g. floor (14/3) is
4 while floor (-14/3) is -5.
Remainder x rem y and modulus x mod y are the same if the signs of x
and y are the same, otherwise they differ and rem takes the sign of x and
mod takes the sign of y. The formulas for remainder and modulus are:
x rem y = x - y * (x div y)
x mod y = x - y * floor(x/y)
Hence, -14 rem 3 equals -2 and -14 mod 3 equals 1. One can view these
results by walking the real axis, starting at -14 and making jumps of 3.
The remainder will be the last negative number one visits, because the first
argument corresponding to x is negative, while the modulus will be the first
positive number one visit, because the second argument corresponding to y
is positive.
- a ≡ -7
abs a ≡ 7
9
The VDM++ Language
abs d ≡ 3
floor a <= a ≡ true
a + d ≡ 4
a * b ≡ 24.5
a / b ≡ 2
a div e ≡ 3
a div d ≡ -2
a mod e ≡ 1
a mod d ≡ -2
-a mod d ≡ -1
a rem e ≡ 1
a rem d ≡ 1
-a rem d ≡ -1
3**2 + 4**2 = 5**2 ≡ true
b < c ≡ false
b > c ≡ true
a <= d ≡ false
b >= e ≡ true
a = e ≡ false
a = 7.0 ≡ true
c <> d ≡ true
abs c < 0 ≡ false
(a div e) * e ≡ 6
The character type contains all the single character elements of the VDM char-
acter set (see Table 12 on page 163).
Name: Char
Symbol: char
10
The VDM++ Language
Examples:
’a’ = ’b’ ≡ false
’1’ = ’c’ ≡ false
’d’ <> ’7’ ≡ true
’e’ = ’e’ ≡ true
Name: Quote
Operators: Assume that q and r in the following denote arbitrary quote values
belonging to an enumerated type T:
Operator Name Type
q = r Equal T ∗ T → bool
q <> r Not equal T ∗ T → bool
The token type consists of a countably infinite set of distinct values, called tokens.
The only operations that can be carried out on tokens are equality and inequality.
In VDM++, tokens cannot be individually represented whereas they can be
written with a mk token around an arbitrary expression. This is a way of enabling
11
The VDM++ Language
Name: Token
Symbol: token
Operators: Assume that s and t in the following denote arbitrary token values:
Operator Name Type
s = t Equal token ∗ token → bool
s <> t Not equal token ∗ token → bool
In the following compound types will be presented. Each of them will contain:
12
The VDM++ Language
For each of the built-in operators the name, the symbol used and the type of
the operator will be given together with a description of its semantics (except
that the semantics of Equality and Inequality is not described, since it follows
the usual semantics). In the semantics description identifiers refer to those used
in the corresponding definition of operator type, e.g. m, m1, s, s1 etc.
A set is an unordered collection of values, all of the same type8 , which is treated
as a whole. All sets in VDM++ are finite, i.e. they contain only a finite number
of elements. The elements of a set type can be arbitrarily complex, they could
for example be sets themselves.
Equation: S = set of A
Constructors:
Set enumeration: {e1, e2, ..., en} constructs a set of the enumer-
ated elements. The empty set is denoted by {}.
Set comprehension: {e | bd1, bd2, ..., bdm & P} constructs a set
by evaluating the expression e on all the bindings for which the pred-
icate P evaluates to true. A binding is either a set binding or a type
binding9 . A set bind bdn has the form pat1, ..., patp in set s,
where pati is a pattern (normally simply an identifier), and s is a
set constructed by an expression. A type binding is similar, in the
sense that in set is replaced by a colon and s is replaced with a type
expression.
8
Note however that it is always possible to find a common type for two values by the use of
a union type (see section 4.2.6.)
9
Notice that type bindings cannot be executed by the interpreter because in general they
are not executable (see section 9 for further information about this).
13
The VDM++ Language
The syntax and semantics for all set expressions are given in section 7.7.
Operators:
Operator Name Type
e in set s1 Membership A ∗ set of A → bool
e not in set s1 Not membership A ∗ set of A → bool
s1 union s2 Union set of A ∗ set of A → set of A
s1 inter s2 Intersection set of A ∗ set of A → set of A
s1 \ s2 Difference set of A ∗ set of A → set of A
s1 subset s2 Subset set of A ∗ set of A → bool
s1 psubset s2 Proper subset set of A ∗ set of A → bool
s1 = s2 Equality set of A ∗ set of A → bool
s1 <> s2 Inequality set of A ∗ set of A → bool
card s1 Cardinality set of A → nat
dunion ss Distributed union set of set of A → set of A
dinter ss Distributed intersection set of set of A → set of A
power s1 Finite power set set of A → set of set of A
Note that the types A, set of A and set of set of A are only meant to illustrate
the structure of the type. For instance it is possible to make a union between
two arbitrary sets s1 and s2 and the type of the resultant set is the union
type of the two set types. Examples of this will be given in section 4.2.6.
Semantics of Operators:
14
The VDM++ Language
15
The VDM++ Language
Constructors:
The syntax and semantics of all sequence expressions are given in sec-
tion 7.8.
Operators:
Operator Name Type
hd l Head seq1 of A → A
tl l Tail seq1 of A → seq of A
len l Length seq of A → nat
elems l Elements seq of A → set of A
inds l Indexes seq of A → set of nat1
l1 ^ l2 Concatenation (seq of A) ∗ (seq of A) → seq of A
conc ll Distributed concatenation seq of seq of A → seq of A
l ++ m Sequence modification seq of A ∗ map nat1 to A → seq of A
l(i) Sequence application seq of A ∗ nat1 → A
l1 = l2 Equality (seq of A) ∗ (seq of A) → bool
l1 <> l2 Inequality (seq of A) ∗ (seq of A) → bool
16
The VDM++ Language
The type A is an arbitrary type and the operands for the concatenation and
distributed concatenation operators do not have to be of the same (A) type.
The type of the resultant sequence will be the union type of the types of
the operands. Examples will be given in section 4.2.6.
Semantics of Operators:
len l1 ≡ 7
hd (l1^l2) ≡ 3
tl (l1^l2) ≡ [1,4,1,5,9,2,2,7,1,8]
l3(len l3) ≡ <Tunisia>
"England"(2) ≡ ’n’
conc [l1,l2] = l1^l2 ≡ true
conc [l1,l1,l2] = l1^l2 ≡ false
elems l3 ≡ { <England>, <Rumania>,
<Colombia>,<Tunisia>}
(elems l1) inter (elems l2) ≡ {1,2}
inds l1 ≡ {1,2,3,4,5,6,7}
17
The VDM++ Language
A map type from a type A to a type B is a type that associates with each element
of A (or a subset of A) an element of B. A map value can be thought of as an
unordered collection of pairs. The first element in each pair is called a key,
because it can be used as a key to get the second element (called the information
part) in that pair. All key elements in a map must therefore be unique. The set of
all key elements is called the domain of the map, while the set of all information
values is called the range of the map. All maps in VDM++ are finite. The
domain and range elements of a map type can be arbitrarily complex, they could
e.g. be maps themselves.
A special kind of map is the injective map. An injective map is one for which
no element of the range is associated with more than one element of the domain.
For an injective map it is possible to invert the map.
In the following this convention will be used: m, m1 and m2 are maps from an
arbitrary type A to another arbitrary type B, ms is a set of map values, a, a1, a2
and an are elements from A while b, b1, b2 and bn are elements from B and P is
a logic predicate. e1 and e2 are arbitrary expressions and s is an arbitrary set.
Map enumeration: {a1 |-> b1, a2 |-> b2, ..., an |-> bn} constructs
a mapping of the enumerated maplets. The empty map will be written
as {|->}.
18
The VDM++ Language
The syntax and semantics of all map expressions are given in section 7.9.
Operators:
Operator Name Type
dom m Domain (map A to B ) → set of A
rng m Range (map A to B ) → set of B
m1 munion m2 Merge (map A to B ) ∗ (map A to B ) → map A to B
m1 ++ m2 Override (map A to B ) ∗ (map A to B ) → map A to B
merge ms Distributed merge set of (map A to B ) → map A to B
s <: m Domain restrict to (set of A) ∗ (map A to B ) → map A to B
s <-: m Domain restrict by (set of A) ∗ (map A to B ) → map A to B
m :> s Range restrict to (map A to B ) ∗ (set of B ) → map A to B
m :-> s Range restrict by (map A to B ) ∗ (set of B ) → map A to B
m(d) Map apply (map A to B ) ∗ A → B
m1 comp m2 Map composition (map B to C ) ∗ (map A to B ) → map A to C
m ** n Map iteration (map A to A) ∗ nat → map A to A
m1 = m2 Equality (map A to B ) ∗ (map A to B ) → bool
m1 <> m2 Inequality (map A to B ) ∗ (map A to B ) → bool
inverse m Map inverse inmap A to B → inmap B to A
19
The VDM++ Language
Examples: Let
m1 = { <France> |-> 9, <Denmark> |-> 4,
<SouthAfrica> |-> 2, <SaudiArabia> |-> 1},
m2 = { 1 |-> 2, 2 |-> 3, 3 |-> 4, 4 |-> 1 },
Europe = { <France>, <England>, <Denmark>, <Spain> }
then:
20
The VDM++ Language
rng m1 ≡ {1,2,4,9}
m2 ** 3 ≡ {1 |-> 4, 2 |-> 1,
3 |-> 2, 4 |-> 3 }
21
The VDM++ Language
The values of a product type are called tuples. A tuple is a fixed length list where
the i’th element of the tuple must belong to the i’th element of the product type.
Equation: T = A1 * A2 * ... * An
Operators:
Operator Name Type
t.#n Select T ∗ nat → Ti
t1 = t2 Equality T ∗ T → bool
t1 <> t2 Inequality T ∗ T → bool
The only operators working on tuples are component select, equality and
inequality. Tuple components may be accessed using the select operator or
by matching against a tuple pattern. Details of the semantics of the tuple
select operator and an example of its use are given in section 7.12.
22
The VDM++ Language
In the following this convention will be used: A is a record type, A1, ..., Am
are arbitrary types, r, r1, and r2 are record values, i1, ..., im are selectors
from the r record value, e1, ..., em are arbitrary expressions.
where identifier denotes both the type name and the tag name.
Equation:
A :: selfirst : A1
selsec : A2
23
The VDM++ Language
or
A :: selfirst : A1
selsec :- A2
or
A :: A1 A2
In the second notation, an equality abstraction field is used for the second
field selsec. The minus indicates that such a field is ignored when com-
paring records using the equality operator. In the last notation the fields
of A can only be accessed by pattern matching (like it is done for tuples) as
the fields have not been named.
In the last notation the fields of A can only be accessed by pattern matching
(as is done for tuples) since the fields have not been named.
The shorthand notation :: used in the two previous examples where the tag
name equals the type name, is the notation most used. The more general
compose notation is typically used if a composite type has to be specified
directly as a component of a more complex type:
It should be noted however that composite types can only be used in type
definitions, and not e.g. in signatures to functions or operations.
Typically composite types are used as alternatives in a union type definition
(see 4.2.6) such as:
MasterA = A | B | ...
24
The VDM++ Language
Operators:
Operator Name Type
r.i Field select A ∗ Id → Ai
r1 = r2 Equality A ∗ A → bool
r1 <> r2 Inequality A ∗ A → bool
is A(r1) Is Id ∗ MasterA → bool
Semantics of Operators:
and let
sc1 = mk Score (<France>, 3, 0, 0, 9),
sc2 = mk Score (<Denmark>, 1, 1, 1, 4),
sc3 = mk Score (<SouthAfrica>, 0, 2, 1, 2) and
sc4 = mk Score (<SaudiArabia>, 0, 1, 2, 1).
Then
sc1.team ≡ <France>
sc4.points ≡ 1
sc2.points > sc3.points ≡ true
is Score(sc4) ≡ true
is bool(sc3) ≡ false
is int(sc1.won) ≡ true
sc4 = sc1 ≡ false
sc4 <> sc2 ≡ true
The equality abstraction field, written using ‘:-’ instead of ‘:’, may be
useful, for example, when working with lower level models of an abstract
syntax of a programming language. For example, one may wish to add a
position information field to a type of identifiers without affecting the true
identity of identifiers:
25
The VDM++ Language
The effect of this will be that the pos field is ignored in equality comparisons,
e.g. the following would evaluate to true:
mk_Id("x",7) = mk_Id("x",9)
Such a map will contain at most one index for a specific identifier, and a
map lookup will be independent of the pos field.
Moreover, the equality abstraction field will affect set expressions. For
example,
{mk_Id("x",7),mk_Id("y",8),mk_Id("x",9)}
will be equal to
{mk_Id("x",?),mk_Id("y",8)}
The union type corresponds to a set-theoretic union, i.e. the type defined by
means of a union type will contain all the elements from each of the components
of the union type. It is possible to use types that are not disjoint in the union
type, even though such usage would be bad practice. However, the union type is
normally used when something belongs to one type from a set of possible types.
The types which constitute the union type are often composite types. This makes
26
The VDM++ Language
it possible, using the is operator, to decide which of these types a given value of
the union type belongs to.
The optional type [T] is a kind of shorthand for a union type T | nil, where nil
is used to denote the absence of a value. However, it is not possible to use the
set {nil} as a type so the only types nil will belong to will be optional types.
Equation: B = A1 | A2 | ... | An
Constructors: None.
Operators:
Operator Name Type
t1 = t2 Equality A ∗ A → bool
t1 <> t2 Inequality A ∗ A → bool
Examples: In this example Expr is a union type whereas Const, Var, Infix and
Cond are composite types defined using the shorthand :: notation.
27
The VDM++ Language
Using union types we can extend the use of previously defined operators.
For instance, interpreting = as a test over bool | nat we have
1 = false ≡ false
Similarly we can take use union types for taking unions of sets and concate-
nating sequences:
{1,2} union {false,true} ≡ {1,2, false,true}
[’a’,’b’]^[<c>,<d>] ≡ [’a’,’b’, <c>,<d>]
In the set union, we take the union over sets of type nat | bool; for the
sequence concatenation we are manipulating sequences of type char | <c>
| <d>.
The object reference type has been added as part of the standard VDM-SL types.
Therefore there is no direct way of restricting the use of object reference types
(and thus of objects) in a way that conforms to pure object oriented principles;
no additional structuring mechanisms than classes are foreseen. From these prin-
ciples it follows that the use of an object reference type in combination with a
type constructor (record, map, set, etc.) should be treated with caution.
An object reference type is denoted by a class name. The class name in the object
reference type must be the name of a class defined in the specification.
The only operator defined for values of this type is the test for equality (‘=’).
Equality is based on references rather than values. That is, if o1 and o2 are two
distinct objects which happen to have the same contents, o1 = o2 will yield false.
Constructors Object references are constructed using the new expression (see
section 7.13).
Operators
Operator Name Type
t1 = t2 Equality A ∗ A → bool
28
The VDM++ Language
class Tree
types
instance variables
protected root: tree := <Empty>;
end Tree
Here we define the type of nodes, which consist of a node value, and ref-
erences to left and right tree objects. Details of access specifiers may be
found in section 14.3.
Such usage can be considered advanced in the sense that functions are used as
values (thus this section may be skipped during the first reading). Function values
may be created by lambda expressions (see below), or by function definitions,
which are described in section 6. Function values can be of higher order in the
sense that they can take functions as arguments or return functions as results.
In this way functions can be Curried such that a new function is returned when
the first set of parameters are supplied (see the examples below).
29
The VDM++ Language
Operators:
Operator Name Type
f(a1,...,an) Function apply A1 ∗ · · · ∗ An → B
f1 comp f2 Function composition (B → C ) ∗ (A → B ) → (A → C )
f ** n Function iteration (A → A) ∗ nat → (A → A)
t1 = t2 Equality A ∗ A → bool
t1 <> t2 Inequality A ∗ A → bool
Note that equality and inequality between type values should be used with
great care. In VDM++ this corresponds to the mathematical equality
(and inequality) which is not computable for infinite values like general
functions. Thus, in the interpreter the equality is on the abstract syntax of
the function value (see inc1 and inc2 below).
Semantics of Operators:
10
Note that the total function arrow can only be used in signatures of totally defined functions
and thus not in a type definition.
30
The VDM++ Language
4.3 Invariants
Id = Type
inv pat == expr
31
The VDM++ Language
where pat is a pattern matching the values belonging to the type Id, and expr is
a truth-valued expression, involving some or all of the identifiers from the pattern
pat.
This function can be used within other invariant, function or operation definitions.
For instance, recall the record type Score defined on page 25. We can ensure
that the number of points awarded is consistent with the number of games won
and drawn using an invariant:
5 Algorithm Definitions
32
The VDM++ Language
Functions and operations can be defined both explicitly (by means of an explicit
algorithm definition) or implicitly (by means of a pre-condition and/or a post
condition). An explicit algorithm definition for a function is called an expression
while for an operation it is called a statement. A pre-condition is a truth-valued
expression which specifies what must hold before the function/operation is evalu-
ated. A pre-condition can only refer to parameter values and global variables (if
it is an operation). A post-condition is also a truth valued expression which spec-
ifies what must hold after the function/operation is evaluated. A post-condition
can refer to the result identifier, the parameter values, the current values of global
variables and the old values of global variables. The old values of global variables
are the values of the variables as they were before the operation was evaluated.
Only operations can refer to the old values of global variables in a post-condition
as functions are not allowed to change the global variables.
6 Function Definitions
In VDM++ we can define first order and higher order functions. A higher order
function is either a Curried function (a function that returns a function as result),
or a function that takes functions as arguments. Furthermore, both first order
and higher order functions can be polymorphic. In general, the syntax for the
definition of a function is:
access = ‘public’
11
Implicitly specified functions and operations cannot in general be executed because their
post-condition does not need to directly relate the output to the input. Often it is done by
specifying the properties the output must satisfy.
33
The VDM++ Language
| ‘private’
| ‘protected’ ;
34
The VDM++ Language
Here is not yet specified may be used as the function body during development of
a model; is subclass responsibility indicates that implementation of this body must
be undertaken by any subclasses.
Details of the access and static specifiers can be found in section 14.3. Note
that a static function may not call non-static operations or functions, and self
expressions cannot be used in the definition of a static function.
map_inter: (map nat to nat) * (map nat to nat) -> map nat to nat
map_inter (m1,m2) ==
(dom m1 inter dom m2) <: m1
pre forall d in set dom m1 inter dom m2 & m1(d) = m2(d)
Note that we could also use the optional post condition to allow assertions about
the result of the function:
35
The VDM++ Language
map_inter: (map nat to nat) * (map nat to nat) -> map nat to nat
map_inter (m1,m2) ==
(dom m1 inter dom m2) <: m1
pre forall d in set dom m1 inter dom m2 & m1(d) = m2(d)
post dom RESULT = dom m1 inter dom m2
map_disj (m1:map nat to nat,m2:map nat to nat) res : map nat to nat ==
(dom m1 inter dom m2) <-: m1 munion
(dom m1 inter dom m2) <-: m2
pre forall d in set dom m1 inter dom m2 & m1(d) = m2(d)
post dom res = (dom m1 union dom m2) \ (dom m1 inter dom m2)
and
forall d in set dom res & res(d) = m1(d) or res(d) = m2(d)
(Note here that an attempt to interpret the post-condition could potentially result
in a run-time error since m1(d) and m2(d) need not both be defined simultane-
ously.)
The functions map inter and map disj can be evaluated by the interpreter, but
the implicit function map inter2 cannot be evaluated. However, in all three cases
the pre- and post-conditions can be used in other functions; for instance from the
definition of map inter2 we get functions pre map inter2 and post map inter2
with the following signatures:
pre map_inter2 : (map nat to nat) * (map nat to nat) +> bool
post map_inter2 : (map nat to nat) * (map nat to nat) *
(map nat to nat) +> bool
36
The VDM++ Language
These kinds of functions are automatically created by the interpreter and they
can be used in other definitions (this technique is called quoting). In general, for
a function f with signature
f : T1 * ... * Tn -> Tr
defining a pre-condition for the function causes creation of a function pre f with
signature
and defining a post-condition for the function causes creation of a function post f
with signature
Functions can also be polymorphic. This means that we can create generic func-
tions that can be used on values of several different types. For this purpose type
parameters (or type variables which are written like normal identifiers prefixed
with a @ sign) are used. Consider the polymorphic function to create an empty
bag:12
Before we can use the above function, we have to instantiate the function empty bag
with a type, for example integers (see also section 7.12):
emptyInt = empty_bag[int]
Now we can use the function emptyInt to create a new bag to store integers.
More examples of polymorphic functions are:
12
The examples for polymorphic functions are taken from [2]. Bags are modelled as maps from
the elements to their multiplicity in the bag. The multiplicity is at least 1, i.e. a non-element
is not part of the map, rather than being mapped to 0.
37
The VDM++ Language
If pre- and or post-conditions are defined for polymorphic functions, the corre-
sponding predicate functions are also polymorphic. For instance if num bag was
defined as
38
The VDM++ Language
Functions may also return functions as results. An example of this is the function
fmap:
fmap[@elem]: (@elem -> @elem) -> seq of @elem -> seq of @elem
fmap (f)(l) ==
if l = []
then []
else [f(hd l)]^(fmap[@elem] (f)(tl l));
7 Expressions
In this subsection we will describe the different kinds of expressions one by one.
Each of them will be described by means of:
39
The VDM++ Language
where p1, ..., pn are patterns, e1, ..., en are expressions which match
the corresponding pattern pi, and e is an expression, of any type, involving
the pattern identifiers of p1, ..., pn. It denotes the value of the ex-
pression e in the context in which the patterns p1, ..., pn are matched
against the corresponding expressions e1, ..., en.
More advanced let expressions can also be made by using local function
definitions. The semantics of doing so is simply that the scope of such
locally defined functions is restricted to the body of the let expression.
In standard VDM-SL the collection of definitions may be mutually recursive.
However, in VDM++ this is not supported by the interpreter. Further-
more, the definitions must be ordered such that all constructs are defined
before they are used.
A let-be-such-that expression has the form:
let b be st e1 in e2
40
The VDM++ Language
map_disj : (map nat to nat) * (map nat to nat) -> map nat to nat
map_disj (m1,m2) ==
let inter_dom = dom m1 inter dom m2
in
inter_dom <-: m1 munion
inter_dom <-: m2
pre forall d in set dom m1 inter dom m2 & m1(d) = m2(d)
They are also convenient for decomposing complex structures into their
components. For instance, using the previously defined record type Score
(page 25) we can test whether one score is greater than another:
41
The VDM++ Language
The last example shows how the optional “be such that” part (be st) can
be used. This part is especially useful when it is known that an element
with some property exists but an explicit expression for such an element is
not known or difficult to write. For instance we can exploit this expression
to write a selection sort algorithm:
Here the first function removes a given element from the given list; the sec-
ond function repeatedly removes the least element in the unsorted portion
of the list, and places it at the head of the sorted portion of the list.
This expression can only be used inside operations which will be described in
section 12. In order to deal with global variables inside the expression part an
extra expression construct is available inside operations.
Syntax: expression = . . .
| def expression
| ... ;
42
The VDM++ Language
The define expression corresponds to a let expression except that the right
hand side expressions may depend on the value of the local and/or global
variable and that it may not be mutually recursive. It denotes the value of
the expression e in the context in which the patterns (or binds) pb1, ...,
pbn are matched against the corresponding expressions e1, ..., en14 .
where copy is defined in the context, lib is global variable (thus lib(copy)
can be considered as looking up the contents of a part of the variable).
The operation GroupRunnerUp expl in section 13.1 also gives an example
of a define expression.
14
If binds are used, it simply means that the values which can match the pattern are further
constrained by the type or set expression as explained in section 8.
43
The VDM++ Language
Examples: Examples using these operators were given in section 4, so none will
be provided here.
44
The VDM++ Language
Semantics: If expressions and cases expressions allow the choice of one from a
number of expressions on the basis of the value of a particular expression.
The if expression has the form:
if e1
then e2
else e3
45
The VDM++ Language
cases e :
p11, p12, ..., p1n -> e1,
... -> ...,
pm1, pm2, ..., pmk -> em,
others -> emplus1
end
where e is an expression of any type, all pij’s are patterns which are
matched one by one against the expression e. The ei’s are expressions of
any type, and the keyword others and the corresponding expression emplus1
are optional. The cases expression denotes the value of the ei expression
evaluated in the context in which one of the pij patterns has been matched
against e. The chosen ei is the first entry where it has been possible to
match the expression e against one of the patterns. If none of the patterns
match e an others clause must be present, and then the cases expression
denotes the value of emplus1 evaluated in the given context.
Examples: The if expression in VDM++ corresponds to what is used in most
programming languages, while the cases expression in VDM++ is more
general than most programming languages. This is shown by the fact that
real pattern matching is taking place, but also because the patterns do not
have to be constants as in most programming languages.
An example of the use of conditional expressions is provided by the speci-
fication of the mergesort algorithm:
46
The VDM++ Language
47
The VDM++ Language
where the mbdi’s and the e are as for a universal quantification. It has the
value true if e is true when evaluated in the context of at least one choice
of bindings from mbd1, mbd2, ..., mbdn, and false otherwise.
The unique existential quantification has the form:
exists1 bd & e
48
The VDM++ Language
types
ExpertId = token;
Expert :: expertid : ExpertId
quali : set of Qualification
inv ex == ex.quali <> ;
Qualification = <Elec> | <Mech> | <Bio> | <Chem>
functions
Syntax: expression = . . .
| iota expression
| ... ;
49
The VDM++ Language
iota bd & e
we have
iota x in set {sc1,sc2,sc3,sc4} & x.team = <France> ≡ sc1
iota x in set {sc1,sc2,sc3,sc4} & x.points > 3 ≡ ⊥
iota x : Score & x.points < x.won ≡ ⊥
Notice that the last example cannot be executed and that the last two
expressions are undefined - in the former case because there is more than
value satisfying the expression, and in the latter because no value satisfies
the expression.
50
The VDM++ Language
where e1 and e2 are numeric expressions. The set range expression denotes
the set of integers from e1 to e2 inclusive. If e2 is smaller than e1 the set
range expression denotes the empty set.
51
The VDM++ Language
subsequence = expression,
‘(’, expression, ‘,’, ‘...’, ‘,’,
expression, ‘)’ ;
52
The VDM++ Language
where the expression e will use the identifiers from the pattern pat (nor-
mally this pattern will simply be an identifier, but the only real requirement
is that exactly one pattern identifier must be present in the pattern). S is
a set of values (normally natural numbers). The bindings of the pattern
identifier must be to some kind of numeric values which then are used to
indicate the ordering of the elements in the resulting sequence. It constructs
a sequence by evaluating the expression e on all the bindings for which the
predicate P evaluates to true.
A subsequence of a sequence l is a sequence formed from consecutive ele-
ments of l; from index n1 up to and including index n2. It has the form:
[ mk Score(<Brazil>,2,0,1,6),
mk Score(<Norway>,1,2,0,5),
mk Score(<Morocco>,1,1,1,4),
mk Score(<Scotland>,0,1,2,1) ]
then:
[GroupA(i).team ≡ [<Brazil>,
| i in set inds GroupA <Norway>,
& GroupA(i).won <> 0] <Morocco>]
[GroupA(i) ≡ [mk Score(<Scotland>,0,1,2,1)]
| i in set inds GroupA
& GroupA(i).won = 0]
GroupA(1,...,2) ≡ [mk Score(<Brazil>,2,0,1,6),
mk Score(<Norway>,1,2,0,5)]
[GroupA(i) ≡ []
| i in set inds GroupA
& GroupA(i).points = 9]
53
The VDM++ Language
where all the domain expressions di and range expressions ri are general
expressions. The empty map must be written as {|->}.
A map comprehension has the form:
where constructs mbd1, ..., mbdn are multiple bindings of variables from
the expressions ed and er to sets (or types). The map comprehension
constructs a mapping by evaluating the expressions ed and er on all the
possible bindings for which the predicate P evaluates to true.
then:
54
The VDM++ Language
Syntax: expression = . . .
| tuple constructor
| ... ;
Examples: Using the map GroupG defined in the preceding example, we have:
mk (2,1,0) in set rng GroupG ≡ true
mk ("Romania",2,1,0) not in set rng GroupG ≡ true
mk (<Romania>,2,1,0) <> mk ("Romania",2,1,0) ≡ true
55
The VDM++ Language
where the type of the expressions (e1, e2, ..., en) matches the type of
the corresponding entrances in the composite type T.
The record modification has the form:
mu (e, id1 |-> e1, id2 |-> e2, ..., idn |-> en)
Further examples are demonstrated in the function win. This function takes
two teams and a set of scores. From the set of scores it locates the scores
corresponding to the given teams (wsc and lsc for the winning and losing
team respectively), then updates these using the mu operator. The set of
teams is then updated with the new scores replacing the original ones.
win : Team * Team * set of Score -> set of Score
win (wt,lt,gp) ==
let wsc = iota sc in set gp & sc.team = wt,
lsc = iota sc in set gp & sc.team = lt
in let new_wsc = mu(wsc, won |-> wsc.won + 1,
points |-> wsc.points + 3),
new_lsc = mu(lsc, lost |-> lsc.lost + 1)
in (gp \ {wsc,lsc}) union {new_wsc, new_lsc}
pre forall sc1, sc2 in set gp &
sc1 <> sc2 <=> sc1.team <> sc2.team
and {wt,lt} subset {sc.team | sc in set gp}
56
The VDM++ Language
Semantics: The field select expression can be used for records and it has already
been explained in section 4.2.5 so no further explanation will be given here.
The apply is used for looking up in a map, indexing in a sequence, and finally
for calling a function. In section 4.2.3 it has already been shown what it
means to look up in a map. Similarly in section 4.2.2 it is illustrated how
indexing in a sequence is performed.
In VDM++ an operation can also be called here. This is not allowed in
standard VDM-SL and because this kind of operation call can modify the
state such usage should be done with care in complex expressions. Note
however that such operation calls are not allowed to throw exceptions.
With such operation calls the order of evaluation can become important.
Therefore the type checker will allow the user to enable or disable operation
calls inside expressions.
The tuple select expression is used to extract a particular component from
a tuple. The meaning of the expression is if e evaluates to some tuple
mk (v1,...,vN) and M is an integer in the range {1,...,N} then e.#M
yields vM. If M lies outside {1,...,N} the expression is undefined.
The function type instantiation is used for instantiating polymorphic func-
tions with the proper types. It has the form:
pf [ t1, ..., tn ]
57
The VDM++ Language
Examples: Recall that GroupA is a sequence (page 53), GroupG is a map (page
54) and selection sort is a function (page 42):
GroupA(1) ≡ mk Score(<Brazil>,2,0,1,6)
GroupG(<Romania>) ≡ mk (2,1,0)
GroupG(<Romania>).#2 ≡ 1
selection sort([3,2,9,1,3]) ≡ [1,2,3,3,9]
As an example of the use of polymorphic functions and function type in-
stantiation, we use the example functions from section 6:
{ -1 |-> 1 }
Syntax: expression = . . .
| new expression ;
An object can be created (also called instantiated) from its class description
using a new expression. The effect of a new expression is that a ‘new’,
unique object as described in class classname is created. The value of the
new expression is a reference to the new object.
If the new expression is invoked with no parameters, an object is created
in which all instance variables take their “default” values (i.e. the values
58
The VDM++ Language
Examples: Suppose we have a class called Queue and that default instances of
Queue are empty. Suppose also that this class contains a constructor (which
will also be called Queue) which takes a single parameter which is a list of
values representing an arbitrary starting queue. Then we can create default
instances of Queue in which the actual queue is empty using the expression
new Queue()
and an instance of Queue in which the actual queue is, say, e1, e2, e3
using the expression
Using the class Tree defined on page 29 we create new Tree instances to
construct nodes:
Syntax: expression = . . .
| self expression ;
self
The self expression returns a reference to the object currently being exe-
cuted. It can be used to simplify the name space in chains of inheritance.
Examples: Using the class Tree defined on page 29 we can specify a subclass
called BST which stores data using the binary search tree approach. We can
then specify an operation which performs a binary search tree insertion:
59
The VDM++ Language
This operation uses a self expression to find the root at which to being
traversal prior to insertion. Further examples are given in section 13.9.
Syntax: expression = . . .
| threadid expression ;
threadid
class WaitNotify
instance variables
waitset : set of nat := {};
operations
60
The VDM++ Language
Awake: () ==> ()
Awake() ==
skip;
sync
mutex(notifyAll, AddToWaitSet, notify);
per Awake => threadid not in set waitset;
end WaitNotify
61
The VDM++ Language
Syntax: expression = . . .
| lambda expression
| ... ;
where the pati are patterns, the Ti are type expressions, and e is the body
expression. The scope of the pattern identifiers in the patterns pati is the
body expression. A lambda expression cannot be polymorphic, but apart
from that, it corresponds semantically to an explicit function definition as
explained in section 6. A function defined by a lambda expression can be
Curried by using a new lambda expression in the body of it in a nested way.
When lambda expressions are bound to an identifier they can also define a
recursive function.
which will return a new lambda expression if it is applied to only one argu-
ment:
62
The VDM++ Language
7.17 Is Expressions
Syntax: expression = . . .
| general is expression
| ... ;
Semantics: The is expression can be used with values that are either basic or
record values (tagged values belonging to some composite type). The is
expression yields true if the given value belongs to the basic type indicated
or if the value has the indicated tag. Otherwise it yields false.
A type judgement is a more general form which can be used for expressions
whose types can not be statically determined. The expression is (e,t) is
equal to true if and only if e is of type t.
63
The VDM++ Language
Syntax: expression = . . .
| isofbaseclass expression
| ... ;
Syntax expression = . . .
| isofclass expression
| ... ;
64
The VDM++ Language
Syntax: expression = . . .
| samebaseclass expression
| ... ;
65
The VDM++ Language
Syntax: expression = . . .
| sameclass expression
| ... ;
66
The VDM++ Language
For all of these operators, the name list version #history op(op1,. . .,opN) is
simply shorthand for #history op(op1) + · · · +#history op(opN).
rA aA rB aB rA fB rC rC rC aC fA
S T
67
The VDM++ Language
Semantics: Names and old names are used to access definitions of functions,
operations, values and state components. A name has the form:
id1‘id2
where id1 and id2 are simple identifiers. If a name consists of only one
identifier, the identifier is defined within scope, i.e. it is defined either locally
as a pattern identifier or variable, or globally within the current module as
a function, operation, value or global variable. Otherwise, the identifier id1
indicates the class name where the construct is defined (see also section 14.1
and appendix B.)
An old name is used to access the old value of global variables in the post
condition of an operation definition (see section 12) and in the post condi-
tion of specification statements (see section 13.15). It has the form:
68
The VDM++ Language
id~
Examples: Names and symbolic literals are used throughout all examples in this
document (see appendix B.2).
For an example of the use of old names, consider the instance variables
defined as:
instance variables
numbers: seq of nat := [];
index : nat := 1;
inv index not in set elems numbers;
IncIndex()
ext wr index : nat
post index = index~ + 1
types
functions
69
The VDM++ Language
In another class we can access this function by using the following call
CGRel‘build_rel(mk_(<A>, <B>))
Semantics: The undefined expression is used to state explicitly that the result
of an expression is undefined. This could for instance be used if it has
not been decided what the result of evaluating the else-branch of an if-
then-else expression should be. When an undefined expression is evaluated
the interpreter will terminate the execution and report that an undefined
expression was evaluated.
Pragmatically use of undefined expressions differs from pre-conditions: use
of a pre-condition means it is the caller’s responsibility to ensure that the
pre-condition is satisfied when the function is called; if an undefined ex-
pression is used it is the called function’s responsibility to deal with error
handling.
Examples: We can check that the type invariant holds before building Score
values:
70
The VDM++ Language
is equal to
Note that however h is bound, the last argument (-1) is never used.
8 Patterns
71
The VDM++ Language
1. A pattern identifier fits any type and can be matched to any value.
If it is an identifier, that identifier is bound to the value; if it is the
don’t-care symbol ‘-’, no binding occurs.
72
The VDM++ Language
Here the identifier top is bound to the head of the sequence GroupA and
the identifier may then be used in the body of the let expression.
In the following examples we use match values:
let a = <France>
in cases GroupA(1).team:
<Brazil> -> "Brazil are winners",
(a) -> "France are winners",
others -> "Neither France nor Brazil are winners"
end;
73
The VDM++ Language
Match values can only match against their own values, so here if the team
at the head of GroupA is <Brazil> then the first clause is matched; if the
team at the head of GroupA is <France> then the second clause is matched.
Otherwise the others clause is matched. Note here that the use of brackets
around a forces a to be considered as a match value.
Set enumerations match patterns to elements of a set. For instance in
the identifiers sc1, sc2, sc3 and sc4 are bound to the four elements of
GroupA. Note that the choice of binding is loose - for instance sc1 may be
bound to [any] element of elems GroupA. In this case if elems GroupA does
not contain precisely four elements, then the expression is not well-formed.
A set union pattern can be used to decompose a set for recursive function
calls. An example of this is the function set2seq which converts a set into
a sequence (with arbitrary order):
In the third cases alternative we see the use of a set union pattern. This
binds s1 and s2 to arbitrary subsets of s such that they partition s. The
Toolbox interpreter always ensures a disjoint partition.
Sequence enumeration patterns can be used to extract specific elements from
a sequence. An example of this is the function promoted which extracts
the first two elements of a seqnce of scores and returns the corresponding
pair of teams:
Here sc1 is bound to the head of the argument sequence, and sc2 is bound
to the second element of the sequence. If promoted is called with a sequence
with fewer than two elements then a runtime error occurs. Note that as we
74
The VDM++ Language
are not interested in the remaining elements of the list we use a don’t care
pattern for the remainder.
The preceding example also demonstrated the use of sequence concatena-
tion patterns. Another example of this is the function quicksort which
implements a standard quicksort algorithm:
values
mk (Awinner,-) = promoted(GroupA);
Record patterns are useful when several fields of a record are used in the
same expression. For instance the following expression constructs a map
from team names to points score:
The function print Expr on page 47 also gives several examples of record
patterns.
75
The VDM++ Language
9 Bindings
forall i, j in set inds list & i < j => list(i) <= list(j)
76
The VDM++ Language
values
access pat1 = e1;
...
access patn = en
Examples: The example below, taken from [4] assigns token values to identifiers
p1 and eid2, an Expert record value to e3 and an Alarm record value to
a1.
types
Period = token;
ExpertId = token;
Expert :: expertid : ExpertId
77
The VDM++ Language
values
As this example shows, a value can depend on other values which are defined
previous to itself.
11 Instance Variables
Both an object instantiated from a class description and the class itself can have
an internal state, also called the instance variables of the object or class. In the
case of objects, we also refer to this state as the global state of the object.
Semantics: The section describing the internal state is preceded by the key-
word instance variables. A list of instance variable definitions and/or
invariant definitions follows. Each instance variable definition consists of
78
The VDM++ Language
an instance variable name with its corresponding type indication and may
also include an initial value and access and static specifiers. Details of the
access and static specifiers can be found in section 14.3.
It is possible to restrict the values of the instance variables by means of
invariant definitions. Each invariant definition, involving one or more in-
stance variables, may be defined over the values of the instance variables
of objects of a class. All instance variables in the class including those
inherited from superclasses are visible in the invariant expression. Each
invariant definition must be a boolean expression that limits the values of
the instance variables to those where the expression is true. All invariant
expressions must be true during the entire lifetime of each object of the
class.
The overall invariant expression of a class is all the invariant definitions of
the class and its superclasses combined by logical and in the order that they
are defined in 1) the superclasses and 2) the class itself.
If a class contains one or more invariant definitions, an operation named
inv classname is implicitly constructed in the class.15 This operation is
private, has no parameters and returns a boolean corresponding to the
execution of the invariant expression.
Example: The following examples show instance variable definitions. The first
class specifies one instance variable:
class GroupPhase
types
instance variables
gps : map GroupName to set of Score;
inv forall gp in set rng gps &
15
Not yet supported by the interpreter.
79
The VDM++ Language
(card gp = 4 and
forall sc in set gp & sc.won + sc.lost + sc.drawn <= 3)
end GroupPhase
12 Operation Definitions
Operations have already been mentioned in section 5. The general form is de-
scribed immediately below, and special operations called constructors which are
used for constructing instances of a class are described in section 12.1.
80
The VDM++ Language
Semantics: Details of the access and static specifiers can be found in section
14.3. Note that a static operation may not call non-static operations or
functions, and self expressions cannot be used in the definition of a static
operation.
The following example of an explicit operation updates the instance vari-
ables of class GroupPhase when one team beats another.
81
The VDM++ Language
The externals field lists the instance variables that the operation will ma-
nipulate. The instance variables listed after the reserved word rd can only
be read whereas the operation can both read and write the variables listed
after wr.
82
The VDM++ Language
The exceptions clause can be used to describe how an operation should deal
with error situations. The rationale for having the exception clause is to give
the user the ability to separate the exceptional cases from the normal cases.
The specification using exceptions does not give any commitment as to how
exceptions are to be signalled, but it gives the means to show under which
circumstances an error situation can occur and what the consequences are
for the result of calling the operation.
The exception clause has the form:
The condition names COND1, . . . , CONDn are identifiers which describe the
kind of error which can be raised16 . The condition expressions c1, . . . ,
cn can be considered as pre-conditions for the different kinds of errors.
Thus, in these expressions the identifiers from the arguments list and the
variables from the externals list can be used (they have the same scope as
the pre-condition). The result expressions r1, . . . , rn can correspondingly
be considered as post-conditions for the different kinds of errors. In these
expressions the result identifier and old values of global variables (which
can be written to) can also be used. Thus, the scope corresponds to the
scope of the post-condition.
Superficially there appears to be some redundancy between exceptions and
pre-conditions here. However there is a conceptual distinction between them
which dictates which should be used and when. The pre-condition specifies
what callers to the operation must ensure for correct behaviour; the excep-
tion clauses indicate that the operation being specified takes responsibility
for error handling when an exception condition is satisfied. Hence normally
exception clauses and pre-conditions do not overlap.
The next example of an operation uses the following instance variable def-
inition:
instance variables
q : Queue
end
This example shows how exceptions with an implicit definition can be used:
16
Notice that these names are purely of mnemonic value, i.e. semantically they are not im-
portant.
83
The VDM++ Language
DEQUEUE() e: [Elem]
ext wr q : Queue
post q~ = [e] ^ q
errs QUEUE_EMPTY: q = [] -> q = q~ and e = nil
12.1 Constructors
Constructors are operations which have the same name as the class in which they
are defined and which create new instances of that class. Their return type must
therefore be the same class name, and if a return value is specified this should be
self though this can optionally be omitted.
13 Statements
In this section the different kind of statements will be described one by one. Each
of them will be described by means of:
84
The VDM++ Language
where p1, ..., pn are patterns, e1, ..., en are expressions which match
the corresponding patterns pi, and s is a statement, of any type, involving
the pattern identifiers of p1, ..., pn. It denotes the evaluation of the
statement s in the context in which the patterns p1, ..., pn are matched
against the corresponding expressions e1, ..., en.
More advanced let statements can also be made by using local function
definitions. The semantics of doing that is simply that the scope of such
locally defined functions is restricted to the body of the let statement.
A let-be-such-that statement has the form
let b be st e in s
85
The VDM++ Language
Note the use of the def statement (section 13.2) here; this is used rather
than a let statement since the right-hand side is an operation call, and
therefore is not an expression.
Syntax: statement = . . .
| def statement
| ... ;
86
The VDM++ Language
secondRoundWinners = [<A>,<B>,<C>,<D>,<E>,<F>,<G>,<H>];
secondRoundRunnersUp = [<B>,<A>,<D>,<C>,<F>,<E>,<H>,<G>]
18
If binds are used it simply means that the values which can match the pattern are further
constrained by the type or set expression as it is explained in section 8.
87
The VDM++ Language
Syntax: statement = . . .
| block statement
| ... ;
instance variables
x:nat;
y:nat;
l:seq1 of nat;
the operation Swap uses a block statement to swap the values of variables
x and y:
Swap : () ==> ()
Swap () ==
(dcl temp: nat := x;
x := y;
88
The VDM++ Language
y := temp
)
89
The VDM++ Language
sd := ec
All of the expressions or operation calls on the right hand sides are executed
or evaluated, and then the results are bound to the corresponding state
designators. The right-hand sides are executed atomically with respect to
invariant evaluation. However in the case of a multi-threaded concurrent
model, execution is not necessarily atomic with respect to task switching.
Examples: The operation in the previous example (Swap) illustrated normal as-
signment. The operation Win sd, a refinement of Win on page 82 illustrates
the use of state designators to assign to a specific map key:
90
The VDM++ Language
functions
operations
class C
instance variables
size : nat;
l : seq of nat;
inv size = len l
operations
add1 : nat ==> ()
add1 (x) ==
91
The VDM++ Language
( l := [x] ^ l;
size := size + 1);
end C
92
The VDM++ Language
The semantics for the cases statement corresponds to the cases expression
described in section 7.4 except for the alternatives which are statements.
Examples: Assuming functions clear winner and winner by more wins and
operation RandomElement with the following signatures:
Alternatively, we could use a cases statement with match value patterns for
this operation:
93
The VDM++ Language
cases true:
(clear_winner(gps(gp))) ->
return ((iota sc in set gps(gp) &
forall sc’ in set gps(gp) \ {sc} &
sc.points > sc’.points).team),
(winner_by_more_wins(gps(gp))) ->
return ((iota sc in set gps(gp) &
forall sc’ in set gps(gp) \ {sc} &
(sc.points > sc’.points) or
(sc.points = sc’.points and
sc.won > sc’.won)).team),
Semantics: There are three kinds of for-loop statements. The for-loop using an
index is known from most high-level programming languages. In addition,
there are two for-loops for traversing sets and sequences. These are espe-
cially useful if access to all elements from a set (or sequence) is needed one
by one.
94
The VDM++ Language
for id = e1 to e2 by e3 do
s
for e in l do
s
95
The VDM++ Language
if elem <> z
then nk := nk^[elem];
return nk
);
A set-for loop can be exploited to return the set of winners of all groups:
96
The VDM++ Language
Semantics: The semantics for the while statement corresponds to the while
statement from traditional programming languages. The form of a while
loop is:
while e do
s
Examples: The while loop can be illustrated by the following example which
uses Newton’s method to approximate the square root of a real number r
within relative error e.
97
The VDM++ Language
instance variables
x:nat;
y:nat;
l:seq1 of nat;
Sort: () ==> ()
Sort () ==
while x < y do
||(BubbleMin(), BubbleMax());
BubbleMin : () ==> ()
BubbleMin () ==
(dcl z:nat := x;
dcl m:nat := l(z);
-- find min val in l(x..y)
for i = x to y do
if l(i) < m
then ( m := l(i);
z := i);
-- move min val to index x
20
Even though the user of the interpreter does not know the order in which these statements
are executed they are always executed in the same order unless the seed option is used.
98
The VDM++ Language
(dcl temp:nat;
temp := l(x);
l(x) := l(z);
l(z) := temp;
x := x+1);
BubbleMax : () ==> ()
BubbleMax () ==
(dcl z:nat := x;
dcl m:nat := l(z);
-- find max val in l(x..y)
for i = x to y do
if l(i) > m
then ( m := l(i);
z := i);
-- move max val to index y
(dcl temp:nat;
temp := l(y);
l(y) := l(z);
l(z) := temp;
y := y-1));
Syntax: statement = . . .
| call statement
| ... ;
99
The VDM++ Language
The call statement calls an operation, opname, and returns the result of
evaluating the operation. Because operations can manipulate global vari-
ables a call statement does not necessarily have to return a value as function
calls do.
If an object designator is specified it must yield an object reference to
an object of a class in which the operation opname is defined, and then the
operation must be specified as public. If no object designator is specified
the operation will be called in the current object. If the operation is defined
in a superclass, it must have been defined as public or protected.
Examples:
Consider the following simple specification of a Stack:
class Stack
instance variables
stack: seq of Elem := [];
operations
100
The VDM++ Language
end Stack
In the example the operation Reset does not have any parameters and does
not return a value whereas the operation Pop returns the top element of the
stack. The stack could be used as follows:
Reset();
....
top := Pop();
self.Reset();
top := self.Pop();
101
The VDM++ Language
return e
or
return
if test
then OpCall()
else return FunCall()
For instance, we can extend the stack class from the previous section with
an operation which examines the top of the stack:
102
The VDM++ Language
exit e
or
exit
always s1 in
s2
103
The VDM++ Language
tixe {
pat1 |-> s1,
...
patn |-> sn
} in s
where pat1, ..., patn are patterns or binds, s, s1, ..., sn are state-
ments. First, statement s is evaluated, and if no exception is raised, the
result is returned as the result of the complete recursive trap statement.
Otherwise, the value is matched in order against each of the patterns pati.
When a match cannot be found, the exception is returned as the result of
the recursive trap statement. If a match is found, the corresponding state-
ment si is evaluated. If this does not raise an exception, the result value
of the evaluation of si is returned as the result of the recursive trap state-
ment. Otherwise, the matching starts again, now with the new exception
value (the result of the evaluation of si).
In the above example, we cannot act upon a possible exception raised within
the body statement of the always statement. By using the trap statement
we can catch these exceptions:
104
The VDM++ Language
Now all exceptions raised within the always statement are captured by the
trap statement. If we want to distinguish between several exception values,
we can use either nested trap statements or the recursive trap statement:
DoCommand : () ==> int
DoCommand () ==
( dcl mem : Memory;
always Free(mem) in
( mem := Allocate();
Command(mem, ...)
)
);
105
The VDM++ Language
| error statement
| ... ;
Examples: The operation SquareRoot on page 97 does not exclude the possi-
bility that the number to be square rooted might be negative. We remedy
this in the operation SquareRootErr:
106
The VDM++ Language
Examples: In the operation Remove in section 13.6 the behaviour of the opera-
tion within the for loop if elem=z is not explicitly stated. Remove2 below
does this.
Syntax: statement = . . .
| start statement
| start list statement ;
Semantics: The start and start list statements have the form:
start(aRef)
startlist(aRef_s)
If a class description includes a thread (see section 16), each object created
from this class will have the ability to operate as a stand-alone virtual
machine, or in other terms: the object has its own processing capability. In
this situation, a new expression creates the ‘process’ leaving it in a waiting
107
The VDM++ Language
state. For such objects VDM++ has a mechanism to change the waiting
state into an active state21 in terms of a predefined operation, which can
be invoked through a start statement.
The explicit separation of object creation and start provides the possibility
to complete the initialisation of a (concurrent) system before the objects
start exhibiting their described behaviour, in this way avoiding problems
that may arise when objects are referred to that are not yet created and/or
connected.
A syntactic variant of the start statement is available to start up a number
of active objects in arbitrary order: the start list statement. The parameter
aRef s to startlist must be a set of object references to objects instantiated
from classes containing a thread.
Examples: Consider the specification of an operating system. A component of
this would be the daemons and other processes started up during the boot
sequence. From this perspective, the following definitions are relevant:
types
runLevel = nat;
instance variables
pInit : map runLevel to set of Process
108
The VDM++ Language
Syntax: statement = . . .
| specification statement ;
Sort2 : () ==> ()
Sort2 () ==
while x < y do
|| (BubbleMin(),
[ext wr l : seq1 of nat
wr y : nat
rd x : nat
pre x < y
post y < y~ and
permutation (l~(x,...,y~),l(x,...,y~)) and
forall i in set {x,...,y} & l(i) < l(y~)]
)
109
The VDM++ Language
14 Top-level Specification
14.1 Classes
Compared to the standard VDM-SL language, VDM++ has been extended with
classes. In this section, the use of classes to create and structure a top-level
specification will be described. With the object oriented facilities offered by
VDM++ it is possible to:
• Describe the functional behaviour of the objects using functions and oper-
ations.
• Describe the dynamic behaviour of the system through threads and syn-
chronisation constraints.
Before the actual facilities are described, the general layout of a class is described.
110
The VDM++ Language
• A class header with the class name and an optional inheritance clause.
• An optional class body.
• A class tail.
The class name as given in the class header is the defining occurrence of the
name of the class. A class name is globally visible, i.e. visible in all other
classes in the specification.
The class name in the class header must be the same as the class name in
the class tail. Furthermore, defining class names must be unique throughout
the specification.
The (optional) class body may consist of:
In general, all constructs defined within a class must have a unique name,
e.g. it is not allowed to define an operation and a type with the same name.
However, it is possible to overload function and operation names (i.e. it is
111
The VDM++ Language
possible to have two or more functions with the same name and two or more
operations with the same name) subject to the restriction that the types of
their input parameters should not overlap. That is, it should be possible
using static type checking alone to determine uniquely and unambiguously
which function/operation definition corresponds to each function/operation
call. Note that this applies not only to functions and operations defined in
the local interface of a class but also to those inherited from superclasses.
Thus, for example, in a design involving multiple inheritance a class C may
inherit a function from a class A and a function with the same name from
a class B and all calls involving this function name must be resolvable in
class C.
14.2 Inheritance
• Its instance variables. This also includes all invariants and their restrictions
on the allowed modifications of the state.
A name conflict occurs when two constructs of the same kind and with the same
name are inherited from different superclasses. Name conflicts must be explicitly
resolved through name qualification, i.e. prefixing the construct with the name
of the superclass and a ‘-sign (back-quote) (see also section 19).
Example: In the first example, we see that inheritance can be exploited to allow
a class definition to be used as an abstract interface which subclasses must
implement:
class Sort
112
The VDM++ Language
instance variables
protected data : seq of int
operations
sort_ascending : () ==> ()
sort_ascending () == is subclass responsibility;
end Sort
functions
operations
sort_ascending : () ==> ()
sort_ascending () == SelectionSort(1);
temp := data(mi);
data(mi) := data(i);
113
The VDM++ Language
data(i) := temp;
SelectionSort(i+1)
)
end SelectionSort
class A
instance variables
i: int := 1;
j: int := 2;
end A
class B is subclass of A
end B
class C is subclass of A
instance variables
i: int := 3;
end C
In the example objects of class D have 3 instance variables: A‘i, A‘j and C‘j.
Note that objects of class D will have only one copy of the instance variables
defined in class A even though this class is a common super class of both class B
114
The VDM++ Language
and C. Thus, in class D the names B‘j, C‘j, D‘j and j are all referring to the same
variable, A‘j. It should also be noticed that the variable name i is ambiguous in
class D as it refers to different variables in class B and class C.
Class attribute: an attribute of a class for which there exists exactly one incar-
nation no matter how many instances (possibly zero) of the class may even-
tually be created. Class attributes in VDM++ correspond to static class
members in languages like C++ and Java. Class (static) attributes can be
referenced by prefixing the name of the attribute with the name of the class
followed by a ‘-sign (back-quote), so that, for example, ClassName‘val
refers to the value val defined in class ClassName.
Instance attribute: an attribute for which there exists one incarnation for each
instance of the class. Thus, an instance attribute is only available in an ob-
ject and each object has its own copy of its instance attributes. Instance
(non-static) attributes can be referenced by prefixing the name of the at-
tribute with the name of the object followed by a dot, so that, for example,
object.op() invokes the operation op in the object denoted by object
(provided that op is visible to object).
Other class components are by default always either class attributes or instance
attributes as follows:
• Thread definitions are always instance attributes. Thus, each active object
has its own thread(s).
22
In practice, constants will generally be static – a non-static constant would represent a
constant whose value may vary from one instance of the class to another which would be more
naturally represented by an instance variable.
115
The VDM++ Language
protected: Only subclasses of the current class may use such members
private: No other class may use such members - they may only be used in the
class in which they are specified.
The default access to any class member is private. That is, if no access specifier
is given for a member it is private.
• Public instance variables may be read (but not written) using the dot (for
object instance variables) or back-quote (for class instance variables) no-
tation e.g. a public instance variable v of an object o may be accessed as
o.v.
• Access specifiers may only be used with type, value, function, operation
and instance variable definitions; they cannot be used with thread or syn-
chronization definitions.
• For inherited classes, the interface to the subclass is the same as the interface
to its superclasses extended with the new definitions within the subclass.
116
The VDM++ Language
Example In the example below use of the different access specifiers is demon-
strated, as well as the default access to class members. Explanation is given
in the comments within the definitions.
class A
types
public Atype = <A> | <B> | <C>
values
public Avalue = 10;
functions
public compare : nat -> Atype
compare(x) ==
if x < Avalue
then <A>
elseif x = Avalue
then <B>
else <C>
instance variables
public v1: nat;
private v2: bool := false;
protected v3: real := 3.14;
operations
protected AInit : nat * bool * real ==> ()
AInit(n,b,r) ==
(v1 := n;
v2 := b;
v3 := r)
end A
117
The VDM++ Language
class B is subclass of A
instance variables
v4 : Atype --inherited from A
operations
BInit: () ==> ()
BInit() ==
(AInit(1,true,2.718); --OK: can access protected members
--in superclass
v4 := compare(v1); --OK since v1 is public
v3 := 3.5; --OK since v3 protected and this
--is a subclass of A
v2 := false --illegal since v2 is private to A
)
end B
class C
instance variables
a: A := new A();
b: B := new B();
operations
118
The VDM++ Language
end C
15 Synchronization Constraints
If a sequential system is specified (in which only one thread of control is active
at a time) only a special case of the general properties is used and no extra
syntax is needed. However, in the course of development from specification to
implementation more differences are likely to appear.
The following default synchronization rules for each object apply in VDM++:
• operations are to be viewed as though they are atomic, from the point of
the caller;
119
The VDM++ Language
a slight difference from the semantics of Ada: in Ada both parties to the
rendez-vous are active objects; in VDM++only the calling party is active)
The synchronization definition blocks of the class description provide the user
with ways to override the defaults described above.
The following gives the syntax used to state rules for accepting the execution of
concurrently callable operations. Some notes are given explaining these features.
The use of implication to express the permission means that truth of the
guard condition (expression) is a necessary but not sufficient condition for
the invocation. The permission predicate is to be read as stating that
if the guard condition is false then there is non-permission. Expressing
the permission in this way allows further similar constraints to be added
without risk of contradiction through inheritance for the subclasses. There
is a default for all operations:
120
The VDM++ Language
sync
mutex(opA, opB);
mutex(opB, opC, opD);
per opD => someVariable > 42;
sync
per opA => #active(opA) + #active(opB) = 0;
per opB => #active(opA) + #active(opB) = 0 and
#active(opB) + #active(opC) + #active(opD) = 0;
per opC => #active(opB) + #active(opC) + #active(opD) = 0;
per opD => #active(opB) + #active(opC) + #active(opD) = 0 and
someVariable > 42;
Note that it is only permitted to have one permission predicate for each
operation. The #active operator is explained below.
A mutex(all) constraint specifies that all of the operations specified in that
class and any superclasses are to be executed mutually exclusively.
121
The VDM++ Language
instance variables
site_map : map URL to Filename := {|->}
The following operations are defined in this class (definitions omitted for
brevity):
ExecuteCGI: URL ==> File Execute a CGI script on the server
RetrieveURL: URL ==> File Transmit a page of html
UploadFile: File * URL ==> () Upload a file onto the server
ServerBusy: () ==> File Transmit a “server busy” page
DeleteURL: URL ==> () Remove an obsolete file
Since the server can support only 10 simultaneous connects, we can only
permit an execute or retrieve operation to be activated if the number already
active is less than 10:
122
The VDM++ Language
Semantics: The object state guard is a boolean expression which depends on the
values of one (or more) instance variable(s) of the object itself. Object state
guards differ from operation pre-conditions in that a call to an an operation
whose permission predicate is false results in the caller blocking until the
predicate is satisfied, whereas a call to an operation whose pre-condition is
false means the operation’s behaviour is unspecified.
Examples: Using the web server example again, we can only allow file removal
if some files already exist:
Constraints for safe execution of the operations Push and Pop in a stack
object can be expressed using an object state guard as:
where maxsize and length are instance variables of the stack object.
It is often possible to express such constraints as a consequence of the
history, for example the empty state of the stack:
Semantics: A queue condition guard acts on requests waiting in the queues for
the execution of the operations. This requires use of a third history function
#req such that #req(A) counts the number of messages which have been
received by the object requesting execution of operation A. Again it is useful
to introduce the function #waiting such that: #waiting(A) = #req(A) -
#act(A), which counts the number of items in the queue.
123
The VDM++ Language
Examples: Once again, with the web server we can only activate the ServerBusy
operation if 100 or more connections are waiting:
The most important use of such expressions containing queue state functions
is for expressing priority between operations. The protocol specified by:
Using the previous example, consider the following situation: the web server
is handling 10 RetrieveURL requests already. While it is dealing with these
requests, two further RetrieveURL requests (from objects O1 and O2 ) and one
ExecuteCGI request (from object O3 ) are received. The permission predicates for
these two operations are false since the number of active RetrieveURL operations
is already 10. Thus these objects block.
Then, one of the active RetrieveURL operations reaches completion. The permis-
sion predicate so far blocking O1 , O2 and O3 will become “true” simultaneously.
This raises the question: which object is allowed to proceed? Or even all of them?
Guard expressions are only reevaluated when an event occurs (in this case the
completion of a RetrieveURL operation). In addition to that the test of a permis-
sion predicate by an object and its (potential) activation is an atomic operation.
This means, that when the first object evaluates its guard expression, it will find it
to be true and activate the corresponding operation (RetrieveURL or ExecuteCGI
124
The VDM++ Language
in this case). The other objects evaluating their guard expressions afterwards
will find that #active(RetrieveURL) + #active(ExecuteCGI) = 10 and thus
remain blocked. Which object is allowed to evaluate the guard expression first is
undefined.
Mutex constraints from base classes and derived classes are simply added. If the
base class and derived class have the mutex definitions MA and MB , respectively,
then the derived class simply has both mutex constraints MA , and MB . The
binding of operation names to actual operations is always performed in the class
where the constraint is defined. Therefore a mutex(all) constraint defined in a
superclass and inherited by a subclass only makes the operations from the base
class mutually exclusive and does not affect operations of the derived class.
class A
125
The VDM++ Language
operations
sync
per reader => #active(writer) = 0;
per writer => #active(reader, writer) = 0;
end A
class B is subclass of A
operations
sync
per reader => #active(newWriter) = 0;
per writer => #active(newWriter) = 0;
per newWriter => #active(reader, writer, newWriter) = 0;
end B
Class A implements reader and writer operations with the permission predicates
specifying the multiple readers-single writer protocol. The derived class B adds
newWriter. In order to ensure deterministic behaviour B also has to add permis-
sion predicates for the inherited operations.
A special situation arises when a subclass overrides an operation from the base
class. The overriding operation is treated as a new operation. It has no permission
predicate (and in particular inherits none) unless one is defined in the subclass.
126
The VDM++ Language
shorthand makes all inherited and locally defined operations mutually exclusive.
Overridden operations (defined in a base class) are not affected. In other words,
all operations, that can be called with an unqualified name (“locally visible op-
erations”) will be mutex to each other.
16 Threads
Objects instantiated from a class with a thread part are called active objects. The
scope of the instance variables and operations of the current class is considered
to extend to the thread specification.
Subclasses inherit threads from superclasses. If a class inherits from several classes
only one of these may declare its own thread (possibly through inheritance).
Furthermore, explicitly declaring a thread in a subclass will override any inherited
thread.
The periodic thread definition can be regarded as the implicit way of describing
the activities in a thread.
Semantics: Given a defined time resolution ∆T, a thread with a periodic obliga-
tion invokes the mentioned operation at the beginning of each time interval
with length expression. This creates the periodic execution of the operation
simulating the discrete equivalent of continuous relations which have to be
maintained between instance variables, parameter values and possibly other
external values obtained through operation invocations. It is not possible
to dynamically change the length of the interval.
127
The VDM++ Language
Examples: Consider a timer class which periodically increments its clock in its
own thread. It provides operations for starting, and stopping timing, and
reading the current time.
class Timer
The Timer has two instance variables the current time and a flag indicating
whether the Timer is active or not (the current time is only incremented if
the Timer is active).
instance variables
curTime : nat := 0;
active : bool := false;
operations
public Start : () ==> ()
Start() ==
(active := true;
curTime := 0);
128
The VDM++ Language
return curTime;
IncTime: () ==> ()
IncTime() ==
if active
then curTime := curTime + 100;
The Timer’s thread ensures that the current time is incremented. We take
one time unit for the Timer to correspond to 10 system time units.
thread
periodic(1000)(IncTime)
end Timer
class Factorial
instance variables
result : nat := 5;
operations
129
The VDM++ Language
if n = 0 then return 1
else (
dcl m : Multiplier;
m := new Multiplier();
m.calculate(1,n);
start(m);
result:= m.giveResult();
return result
)
end Factorial
class Multiplier
instance variables
i : nat1;
j : nat1;
k : nat1;
result : nat1
operations
doit : () ==> ()
doit() ==
(
if i = j then result := i
else (
dcl p : Multiplier;
dcl q : Multiplier;
p := new Multiplier();
q := new Multiplier();
start(p);start(q);
k := (i + j) div 2;
-- division with rounding down
p.calculate(i,k);
q.calculate(k+1,j);
result := p.giveResult() * q.giveResult ()
130
The VDM++ Language
)
);
sync
-- cyclic constraints allowing only the
-- sequence calculate; doit; giveResult
thread
doit();
end Multiplier
This version of VDM++ is based on the ISO/VDM-SL standard, but a few differ-
ences exist. These differences are both syntactical and semantical, and are mainly
due to the extensions of the language and to requirements to make VDM++ con-
structs executable23 .
Syntactical differences:
23
The semantics mentioned here is the semantics of the interpreter.
131
The VDM++ Language
132
The VDM++ Language
18 Static Semantics
VDM specifications that are syntactically correct according to the syntax rules
do not necessarily obey the typing and scoping rules of the language. The well-
formedness of a VDM specification can be checked by the static semantics checker.
In the Toolbox such a static semantics checker (for programming languages this
is normally referred to as a type checker) is also present.
133
The VDM++ Language
In the Toolbox this means that the static semantics checker can be called for
either possible correctness or definite correctness. However, it should be noted
that only very simple specifications will be able to pass the definite well-formed-
ness check. Thus, for practical use the possible well-formedness is most useful.
if a = true
then a + 1
else not a
where a has the type nat | bool (the union type of nat and bool). The reader can
easily see that this expression is ill-formed if a is equal to true because then it will
be impossible to add one to a. However, since such expressions can be arbitrarily
complex this can in general not be checked statically. In this particular example
possible well-formedness will yield true while definite well-formedness will yield
false.
19 Scope Conflicts
A name conflict occurs when two constructs with the same name (i.e. identified by
the same identifier) are visible in the same scope. This is also true when two such
constructs are not in the same language category, e.g. a type and an operation
with the same name. A specification with a naming conflict is considered to be
erroneous.
In case both constructs are defined in the same class, then the conflict can not
be resolved other than by renaming one of the constructs. If they are defined in
different classes, then the conflict can be resolved through name qualification, i.e.
one of the constructs is preceded by the name of the class in which it is defined
and a ‘‘’ (backquote) separator, so e.g.
types
Queue = seq of ComplexTypes‘RealNumber
134
The VDM++ Language
name qualification is used to define the type Queue in terms of a type RealNumber
defined in class ComplexTypes.
Note that only name qualification in which a class name is used to resolve the
naming conflict uses the ‘‘’ symbol as a separator; a ‘.’ (dot) symbol is used to
‘qualify’ ordinary values and/or objects. E.g. the notation
o.i
135
The VDM++ Language
References
[1] Reference manual for the ada programming language. Tech. rep., United
States Government (Department of Defence), American National Standards
Institute, 1983.
[2] Dawes, J. The VDM-SL Reference Guide. Pitman, 1991. ISBN 0-273-03151-
1.
[3] Dürr, E. Syntactic description of the vdm++ language. Tech. rep., CAP
Gemini, P.O.Box 2575, 3500 GN Utrecht, NL, September 1992.
[4] Fitzgerald, J., and Jones, C. Proof in VDM: case studies. Springer-
Verlag FACIT Series, 1998, ch. Proof in the Validation of a Formal Model of
a Tracking System for a Nuclear Plant. To appear.
136
The VDM++ Language
A.1 Document
document = class, { class } ;
A.2 Classes
class = ‘class’, identifier, [ inheritance clause ],
[ class body ],
‘end’, identifier ;
A.3 Definitions
class body = definition block, { definition block } ;
137
The VDM++ Language
access = ‘public’
| ‘private’
| ‘protected’ ;
138
The VDM++ Language
139
The VDM++ Language
140
The VDM++ Language
141
The VDM++ Language
142
The VDM++ Language
143
The VDM++ Language
A.4 Expressions
expression list = expression, { ‘,’, expression } ;
144
The VDM++ Language
| apply
| field select
| tuple select
| function type instantiation
| lambda expression
| new expression
| self expression
| threadid expression
| general is expression
| undefined expression
| isofbaseclass expression
| isofclass expression
| samebaseclass expression
| sameclass expression
| act expression
| fin expression
| active expression
| req expression
| waiting expression
| name
| old name
| symbolic literal ;
145
The VDM++ Language
146
The VDM++ Language
| sequence length
| sequence elements
| sequence indices
| distributed sequence concatenation
| map domain
| map range
| distributed map merge ;
floor = ‘floor’ ;
not = ‘not’ ;
147
The VDM++ Language
148
The VDM++ Language
| set union
| set difference
| set intersection
| sequence concatenate
| map or sequence modify
| map merge
| map domain restrict to
| map domain restrict by
| map range restrict to
| map range restrict by
| composition
| iterate ;
149
The VDM++ Language
equal = ‘=’ ;
approx = ‘˜=’ ;
or = ‘or’ ;
and = ‘and’ ;
imply = ‘=>’ ;
subset = ‘subset’ ;
150
The VDM++ Language
composition = ‘comp’ ;
iterate = ‘**’ ;
151
The VDM++ Language
152
The VDM++ Language
153
The VDM++ Language
154
The VDM++ Language
A.4.26 Names
A.6 Statements
statement = let statement
| let be statement
| def statement
| block statement
| general assign statement
| if statement
| cases statement
| sequence for loop
| set for loop
| index for loop
155
The VDM++ Language
| while loop
| nondeterministic statement
| call statement
| specification statement
| start statement
| start list statement
| return statement
| always statement
| trap statement
| recursive trap statement
| exit statement
| error statement
| identity statement ;
156
The VDM++ Language
157
The VDM++ Language
158
The VDM++ Language
A.7.1 Patterns
159
The VDM++ Language
A.7.2 Bindings
160
The VDM++ Language
B Lexical Specification
B.1 Characters
The character set is shown in Table 12, with the forms of characters used in this
document. Notice that this character set corresponds exactly to the ASCII (or
ISO 646) syntax.
The plain letters and the keyword letters are displayed in Table 12 (in a document
the keyword letters simply use the corresponding small letters). The distinguished
letters use the corresponding capital and lower-case letters where the whole quote
161
The VDM++ Language
literal is preceded by “<” and followed by “>” (note that quote literals can also
use underscores and digits). The Greek letters can also be used with a number
sign “#” followed by the corresponding letter (this information is used by the
LATEX pretty printer such that the Greek letters can be produced). All delimiter
characters (in the ASCII version of the standard) are listed in Table 12. In the
standard a distinction between delimiter characters and compound delimiters are
made. We have chosen not to use this distinction in this presentation. Please
also notice that some of the delimiters in the mathematical syntax are keywords
in the ASCII syntax which is used here.
162
The VDM++ Language
plain letter:
a b c d e f g h i j k l m
n o p q r s t u v w x y z
A B C D E F G H I J K L M
N O P Q R S T U V W X Y Z
keyword letter:
a b c d e f g h i j k l m
n o p q r s t u v w x y z
delimiter character:
, : ; = ( ) | - [ ]
{ } + / < > <= >= <> .
* -> +> ==> || => <=> |-> <: :>
<-: :-> & == ** ^ ++
digit:
0 1 2 3 4 5 6 7 8 9
octal digit:
0 1 2 3 4 5 6 7
other characters:
‘ ’ " @ ~
newline:
white space:
These have no graphic form, but are a combination of white space and line
break. There are two separators: without line break (white space) and with
line break (newline).
163
The VDM++ Language
B.2 Symbols
Note that the hyphen which can be used in identifiers is written as a low line (also
known as an underscore “ ”), whereas it is translated to “-” in the mathematical
164
The VDM++ Language
syntax. All identifiers beginning with one of the reserved prefixes are reserved:
init , inv , is , mk , post and pre .
165
The VDM++ Language
Sequence Interpretation
‘\\’ backslash character
‘\r’ return character
‘\n’ newline character
‘\t’ tab character
‘\f’ formfeed character
‘\e’ escape character
‘\a’ alarm (bell)
‘\x’ digit,digit hex representation of character
(e.g. \x41 is ‘A’)
‘\c’ character control character
(e.g. \c A ≡ \x01)
‘\’ octal digit, octal digit, octal digit octal representation of character
‘\"’ the " character
‘\’’ the ’ character
166
The VDM++ Language
C Operator Precedence
The precedence ordering for operators in the concrete syntax is defined using
a two-level approach: operators are divided into families, and an upper-level
precedence ordering, >, is given for the families, such that if families F1 and F2
satisfy
F1 > F2
then every operator in the family F1 is of a higher precedence than every operator
in the family F2 .
combinators > applicators > evaluators > relations > connectives >
constructors
167
The VDM++ Language
iterate = ‘**’ ;
composition = ‘comp’ ;
applicator = subsequence
| apply
| function type instantiation
| field select ;
168
The VDM++ Language
The family of evaluators is divided into nine groups, according to the type of
expression they are used in.
arithmetic infix operator = ‘+’ | ‘-’ | ‘*’ | ‘/’ | ‘rem’ | ‘mod’ | ‘div’ ;
169
The VDM++ Language
This family includes all the relational operators whose results are of type bool.
All operators in the Relations family have equal precedence. Typing dictates that
there is no meaningful way of using them adjacently.
170
The VDM++ Language
This family includes all the logical operators whose result is of type bool.
This family includes all the operators used to construct a value. Their priority
is given either by brackets, which are an implicit part of the operator, or by the
syntax.
C.7 Grouping
Connectives: The ‘=>’ operator has right grouping. The other operators are
associative and therefore right and left grouping are equivalent.
171
The VDM++ Language
Below is a list of the symbols which are different in the mathematical syntax and
the ASCII syntax:
172
The VDM++ Language
173
The VDM++ Language
E Standard Libraries
The Math library is defined in the math.vpp file. It provides the following math
functions:
Functions Pre-conditions
sin: real +> real Sine
acos: real -> real Inverse cosine The argument is not in the inter-
val from -1 to 1 (both inclusive).
pi = 3.14159265358979323846
If the functions are applied with arguments that violate possible pre-conditions
they will return values that are not proper VDM++ values, Inf (infinity, e.g.
tan(pi/2)) and NaN (not a number, e.g. sqrt (-1)).
$TOOLBOXHOME/stdlib/math.vpp
should be added to the current project. This contains the class MATH. To access
the functions in this class, instances of the class must be created; however since
174
The VDM++ Language
values are class attributes, pi may be accessed directly. The example below
demonstrates this:
class UseLib
types
coord :: x : real
y : real
functions
end UseLib
E.2 IO Library
The IO library is defined in the io.vpp file, and it is located in the directory
$TOOLBOXHOME/stdlib/. It provides the IO functions and operations listed below.
Each read/write function or operation returns a boolean value (or a tuple with
a boolean component) representing the success (true) or failure (false) of the
corresponding IO action.
175
The VDM++ Language
filedirective = <start>|<append>
ferror:() ==> seq of char The read/write functions and operations return
false if an error occurs. In this case an internal error string will be set. This
operation returns this string and sets it to "".
As an example of the use of the IO library, consider a web server which maintains
a log of page hits:
176
The VDM++ Language
class LoggingWebServer
values
logfilename : seq1 of char = "serverlog"
instance variables
io : IO := new IO();
functions
URLtoString : URL -> seq of char
URLtoString = ...
operations
RetrieveURL : URL ==> File
RetrieveURL(url) ==
(def _ = io.fecho(logfilename, URLtoString(url)^"\n", <append>);
...
);
end LoggingWebServer
177
The VDM++ Language
Index
abs, 8 tl, 16
and, 5 union, 14
card, 14 ()
comp function apply, 30
function composition, 30 map apply, 19
map composition, 19 sequence apply, 16
conc, 16 **, 19
dinter, 14 function iteration, 30
div, 8 numeric power, 8
dom, 19 *, 8
dunion, 14 tuple type, 22
elems, 16 ++
floor, 8 map override, 19
hd, 16 sequence modification, 16
in set, 14 +>, 30
inds, 16 +, 8
inmap to, 18 ->, 30
inter, 14 -, 8
inverse, 19 .
len, 16 record field selector, 25
map to, 18 /, 8
merge, 19 :->, 19
mk :-, 24
record constructor, 24 ::, 24
token value, 12 :>, 19
tuple constructor, 22 <-:, 19
mod, 8 <:, 19
munion, 19 <=>, 5
not in set, 14 <=, 8
not, 5 <>
or, 5 boolean inequality, 5
power, 14 char inequality, 10
psubset, 14 function inequality, 30
rng, 19 map inequality, 19
seq of, 16 numeric inequality, 8
seq1 of, 16 optional inequality, 27
set of, 13 quote inequality, 11
subset, 14 quote value, 11
178
The VDM++ Language
179
The VDM++ Language
180
The VDM++ Language
181
The VDM++ Language
182
The VDM++ Language
183
The VDM++ Language
184