Download as pdf or txt
Download as pdf or txt
You are on page 1of 171

Programming with Contracts in C++20

Björn Fahller

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 1/171
What is a contract?
contract
 noun con·tract | \ˈkän-ˌtrakt  \

Definition of contract 
(Entry 1 of 3)

1:

a: binding agreement between two or more persons or parties - especially : one legally enforceable
// If he breaks the contract, he'll be sued.

b: a business arrangement for the supply of goods or services at a fixed price


// make parts on contract

c: the act of marriage or an agreement to marry

2: a document describing the terms of a contract


// Have you signed the contract yet?

3: the final bid to win a specified number of tricks in bridge

4: an order or arrangement for a hired assassin to kill someone


// His enemies put out a contract on him.

https:////w.merriam-webster.com/dictionary/contract

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 2/171
What is a contract?
contract In SW design:
 noun con·tract | \ˈkän-ˌtrakt  \
A formalized agreement, regarding
Definition of contract 
program correctness, between a
(Entry 1 of 3)
user and the implementation of
1: a component.
a: binding agreement between two or more persons or parties - especially : one legally enforceable
// If he breaks the contract, he'll be sued.

b: a business arrangement for the supply of goods or services at a fixed price


// make parts on contract

c: the act of marriage or an agreement to marry

2: a document describing the terms of a contract


// Have you signed the contract yet?

3: the final bid to win a specified number of tricks in bridge

4: an order or arrangement for a hired assassin to kill someone


// His enemies put out a contract on him.

https:////w.merriam-webster.com/dictionary/contract

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 3/171
What is a contract?
contract In SW design:
 noun con·tract | \ˈkän-ˌtrakt  \
A formalized agreement, regarding
Definition of contract 
program correctness, between a
(Entry 1 of 3)
user and the implementation of
1: a component.
a: binding agreement between two or more persons or parties - especially : one legally enforceable
// If he breaks the contract, he'll be sued.

b: a business arrangement for the supply of goods or services at a fixed price


// make parts on contract

c: the act of marriage or an agreement to marry

2: a document describing the terms of a contract


// Have you signed the contract yet?

3: the final bid to win a specified number of tricks in bridge

4: an order or arrangement for a hired assassin to kill someone


// His enemies put out a contract on him.

https:////w.merriam-webster.com/dictionary/contract

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 4/171
Contracts


Object-oriented Software
Construction
– Bertrand Meyer - 1988
– ISBN 978-0136290490

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 5/171
Contracts


Preconditions

Postconditions

Class invariants

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 6/171
Ringbuffer example

ringbuffer <int,12> b;
b.push_back(1);
b.push_back(2);
b.push_back(5);
b.pop_front(); // 1
b.push_back(8);
b.pop_front(); // 2
b.push_back(11);
b.push_back(13);
b.push_back(15);
b.push_back(21);
b.push_back(23);
b.push_back(24);

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 7/171
Ringbuffer example

ringbuffer <int,12> b;
b.push_back(1);
b.push_back(2);
b.push_back(5);
b.pop_front(); // 1
b.push_back(8);
b.pop_front(); // 2
b.push_back(11);
b.push_back(13);
b.push_back(15);
b.push_back(21);
b.push_back(23);
b.push_back(24);

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 8/171
Ringbuffer example

ringbuffer <int,12> b; 1
b.push_back(1);
b.push_back(2);
b.push_back(5);
b.pop_front(); // 1
b.push_back(8);
b.pop_front(); // 2
b.push_back(11);
b.push_back(13);
b.push_back(15);
b.push_back(21);
b.push_back(23);
b.push_back(24);

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 9/171
Ringbuffer example

ringbuffer <int,12> b; 1
b.push_back(1);
b.push_back(2);

2
b.push_back(5);
b.pop_front(); // 1
b.push_back(8);
b.pop_front(); // 2
b.push_back(11);
b.push_back(13);
b.push_back(15);
b.push_back(21);
b.push_back(23);
b.push_back(24);

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 10/171
Ringbuffer example

ringbuffer <int,12> b; 1
b.push_back(1);
b.push_back(2);

2
b.push_back(5);
b.pop_front(); // 1
b.push_back(8);
b.pop_front(); // 2

5
b.push_back(11);
b.push_back(13);
b.push_back(15);
b.push_back(21);
b.push_back(23);
b.push_back(24);

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 11/171
Ringbuffer example

ringbuffer <int,12> b; 1
b.push_back(1);
b.push_back(2);

2
b.push_back(5);
b.pop_front(); // 1
b.push_back(8);
b.pop_front(); // 2

5
b.push_back(11);
b.push_back(13);
b.push_back(15);
b.push_back(21);
b.push_back(23);
b.push_back(24);

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 12/171
Ringbuffer example

ringbuffer <int,12> b;
b.push_back(1);
b.push_back(2);

2
b.push_back(5);
b.pop_front(); // 1
b.push_back(8);
b.pop_front(); // 2

5
b.push_back(11);
b.push_back(13);
b.push_back(15);
b.push_back(21);
b.push_back(23);
b.push_back(24);

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 13/171
Ringbuffer example

ringbuffer <int,12> b;
b.push_back(1);
b.push_back(2);

2
b.push_back(5);
b.pop_front(); // 1
b.push_back(8);
b.pop_front(); // 2

5
b.push_back(11);
b.push_back(13);
b.push_back(15);

8
b.push_back(21);
b.push_back(23);
b.push_back(24);

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 14/171
Ringbuffer example

ringbuffer <int,12> b;
b.push_back(1);
b.push_back(2);

2
b.push_back(5);
b.pop_front(); // 1
b.push_back(8);
b.pop_front(); // 2

5
b.push_back(11);
b.push_back(13);
b.push_back(15);

8
b.push_back(21);
b.push_back(23);
b.push_back(24);

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 15/171
Ringbuffer example

ringbuffer <int,12> b;
b.push_back(1);
b.push_back(2);
b.push_back(5);
b.pop_front(); // 1
b.push_back(8);
b.pop_front(); // 2

5
b.push_back(11);
b.push_back(13);
b.push_back(15);

8
b.push_back(21);
b.push_back(23);
b.push_back(24);

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 16/171
Ringbuffer example

ringbuffer <int,12> b;
b.push_back(1);
b.push_back(2);
b.push_back(5);
b.pop_front(); // 1
b.push_back(8);
b.pop_front(); // 2

5
b.push_back(11);
b.push_back(13);
b.push_back(15);

8
b.push_back(21);
b.push_back(23); 11
b.push_back(24);

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 17/171
Ringbuffer example

ringbuffer <int,12> b;
b.push_back(1);
b.push_back(2);
b.push_back(5);
b.pop_front(); // 1
b.push_back(8);
b.pop_front(); // 2

5
b.push_back(11);
b.push_back(13);
b.push_back(15);

8
b.push_back(21);
b.push_back(23); 11
b.push_back(24); 13

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 18/171
Ringbuffer example

ringbuffer <int,12> b;
b.push_back(1);
b.push_back(2);
b.push_back(5);
b.pop_front(); // 1
b.push_back(8);
b.pop_front(); // 2

5
b.push_back(11);
b.push_back(13);
b.push_back(15);

8
b.push_back(21);
b.push_back(23); 11
b.push_back(24); 15
13

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 19/171
Ringbuffer example

ringbuffer <int,12> b;
b.push_back(1);
b.push_back(2);
b.push_back(5);
b.pop_front(); // 1
b.push_back(8);
b.pop_front(); // 2

5
b.push_back(11);
b.push_back(13);
b.push_back(15);

21

8
b.push_back(21);
b.push_back(23); 11
b.push_back(24); 15
13

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 20/171
Ringbuffer example

ringbuffer <int,12> b;
b.push_back(1);
b.push_back(2);
b.push_back(5);
b.pop_front(); // 1
b.push_back(8);
b.pop_front(); // 2

23

5
b.push_back(11);
b.push_back(13);
b.push_back(15);

21

8
b.push_back(21);
b.push_back(23); 11
b.push_back(24); 15
13

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 21/171
Ringbuffer example

ringbuffer <int,12> b;
b.push_back(1);
b.push_back(2);

24
b.push_back(5);
b.pop_front(); // 1
b.push_back(8);
b.pop_front(); // 2

23

5
b.push_back(11);
b.push_back(13);
b.push_back(15);

21

8
b.push_back(21);
b.push_back(23); 11
b.push_back(24); 15
13

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 22/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public:

ringbuffer();

int size() const;

void push_back(T);

T pop_front();

};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 23/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public:

ringbuffer(); Precondition:
int size() const;

void push_back(T);

T pop_front();

};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 24/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public:

ringbuffer(); Precondition:
int size() const;

An obligation that
the caller must fulfill
void push_back(T);
for the program to
be correct.

T pop_front();

};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 25/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public:

ringbuffer(); Precondition:
int size() const; A precondition may
refer to parameter values
or the objects state, An obligation that
or both the caller must fulfill
void push_back(T);
for the program to
be correct.

T pop_front();

};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 26/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public:

ringbuffer(); Precondition:
int size() const;

An obligation that
the caller must fulfill
void push_back(T);
for the program to
be correct.

T pop_front();

};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 27/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public:

ringbuffer(); Precondition:
int size() const;

An obligation that
It almost never makes
sense to have a the caller must fulfill
void push_back(T); precondition on a for the program to
default constructor! be correct.

T pop_front();

};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 28/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public:

ringbuffer(); Precondition:
int size() const;

An obligation that
the caller must fulfill
void push_back(T);
for the program to
be correct.

T pop_front();

};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 29/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public:

ringbuffer(); Precondition:
int size() const;

An obligation that
the caller must fulfill
void push_back(T);
for the program to
Functions that query
be correct.
the state of an object
T pop_front(); rarely has any
preconditions.

};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 30/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public:

ringbuffer(); Precondition:
int size() const;

An obligation that
the caller must fulfill
void push_back(T);
for the program to
be correct.

T pop_front();

};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 31/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public:

ringbuffer(); Precondition:
Choose between:
int size() const;
Define behaviour when
full, or make not-full An obligation that
a precondition. the caller must fulfill
void push_back(T);
for the program to
be correct.

T pop_front();

};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 32/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public:

ringbuffer(); Precondition:
int size() const;

An obligation that
the caller must fulfill
void push_back(T);
for the program to
// requires: size() < N be correct.

T pop_front();

};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 33/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public:

ringbuffer(); Precondition:
int size() const;

An obligation that
the caller must fulfill
void push_back(T);
for the program to
// requires: size() < N be correct.

T pop_front();

};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 34/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public:

ringbuffer(); Precondition:
Choose between:
int size() const;
Define behaviour when
empty, or make not-empty An obligation that
a precondition. the caller must fulfill
void push_back(T);
for the program to
// requires: size() < N be correct.

T pop_front();

};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 35/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public:

ringbuffer(); Precondition:
int size() const;

An obligation that
the caller must fulfill
void push_back(T);
for the program to
// requires: size() < N be correct.

T pop_front();
// requires: size() > 0

};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 36/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public:

ringbuffer(); Postcondition:
int size() const;

void push_back(T);
// requires: size() < N

T pop_front();
// requires: size() > 0

};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 37/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public:

ringbuffer(); Postcondition:
int size() const;

A guarantee from
the implementation
void push_back(T);
regarding the effect
// requires: size() < N of a legal call.

T pop_front();
// requires: size() > 0

};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 38/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public:

ringbuffer(); Postcondition:
A postcondition
int size() const; may refer to return value
or the objects state, or both,
sometimes dependent on A guarantee from
parameter values the implementation
void push_back(T);
regarding the effect
// requires: size() < N of a legal call.

T pop_front();
// requires: size() > 0

};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 39/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public:

ringbuffer(); Postcondition:
int size() const;

A guarantee from
the implementation
void push_back(T);
regarding the effect
// requires: size() < N of a legal call.

T pop_front();
// requires: size() > 0

};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 40/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public:

ringbuffer(); Postcondition:
// ensures: size() /= 0
int size() const;

A guarantee from
the implementation
void push_back(T);
regarding the effect
// requires: size() < N of a legal call.

T pop_front();
// requires: size() > 0

};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 41/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public:

ringbuffer(); Postcondition:
// ensures: size() /= 0
int size() const;

A guarantee from
the implementation
void push_back(T);
regarding the effect
// requires: size() < N of a legal call.

T pop_front();
// requires: size() > 0

};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 42/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public:

ringbuffer(); Postcondition:
// ensures: size() /= 0
int size() const;

A guarantee from
the implementation
void push_back(T);
regarding the effect
// requires: size() < N of a legal call.

T pop_front();
// requires: size() > 0

};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 43/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public:

ringbuffer(); Postcondition:
// ensures: size() /= 0
int size() const;

A guarantee from
the implementation
void push_back(T);
regarding the effect
// requires: size() < N of a legal call.
// ensures: size() /= old size()+1

T pop_front();
// requires: size() > 0

};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 44/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public:

ringbuffer(); Postcondition:
// ensures: size() /= 0
int size() const;

A guarantee from
the implementation
void push_back(T t);
regarding the effect
// requires: size() < N of a legal call.
// ensures: size() /= old size()+1

T pop_front();
// requires: size() > 0

};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 45/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public:

ringbuffer(); Postcondition:
// ensures: size() /= 0
int size() const;
const T& back() const;
A guarantee from
the implementation
void push_back(T t);
regarding the effect
// requires: size() < N of a legal call.
// ensures: size() /= old size()+1
// back() /= t
T pop_front();
// requires: size() > 0

};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 46/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public:

ringbuffer(); Postcondition:
// ensures: size() /= 0
int size() const;
const T& back() const;
// requires: size() > 0 A guarantee from
the implementation
void push_back(T t);
regarding the effect
// requires: size() < N of a legal call.
// ensures: size() /= old size()+1
// back() /= t
T pop_front();
// requires: size() > 0

};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 47/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public:

ringbuffer(); Postcondition:
What/=
// ensures: size() if an
0 exception
int size() const; is thrown?
const T& back() const;
// requires: size() > 0 A guarantee from
the implementation
void push_back(T t);
regarding the effect
// requires: size() < N of a legal call.
// ensures: size() /= old size()+1
// back() /= t
T pop_front();
// requires: size() > 0

};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 48/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public:

ringbuffer(); Postcondition:
// ensures: size() /= 0
int size() const; Postconditions handles
return. If an exception is
const T& back() const;
// requires: size() > 0 thrown, there is no A guarantee from
post condition. the implementation
void push_back(T t);
regarding the effect
// requires: size() < N of a legal call.
// ensures: size() /= old size()+1
// back() /= t
T pop_front();
// requires: size() > 0

};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 49/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public:

ringbuffer(); Postcondition:
// ensures: size() /= 0
int size() const;
const T& back() const;
// requires: size() > 0 A guarantee from
the implementation
void push_back(T t);
regarding the effect
// requires: size() < N of a legal call.
// ensures: size() /= old size()+1
// back() /= t
T pop_front();
// requires: size() > 0

};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 50/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public:

ringbuffer(); Postcondition:
// ensures: size() /= 0
int size() const;
const T& back() const;
// requires: size() > 0 A guarantee from
the implementation
void push_back(T t);
regarding the effect
// requires: size() < N of a legal call.
// ensures: size() /= old size()+1
// back() /= t
T pop_front();
// requires: size() > 0
// ensures: size() /= old size()-1

};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 51/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public:

ringbuffer(); Postcondition:
// ensures: size() /= 0
int size() const;
const T& back() const;
// requires: size() > 0 A guarantee from
const T& front() const; the implementation
void push_back(T t);
regarding the effect
// requires: size() < N of a legal call.
// ensures: size() /= old size()+1
// back() /= t
T pop_front();
// requires: size() > 0
// ensures: size() /= old size()-1
// return /= old front();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 52/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public:

ringbuffer(); Postcondition:
// ensures: size() /= 0
int size() const;
const T& back() const;
// requires: size() > 0 A guarantee from
const T& front() const; the implementation
// requires: size() > 0
void push_back(T t);
regarding the effect
// requires: size() < N of a legal call.
// ensures: size() /= old size()+1
// back() /= t
T pop_front();
// requires: size() > 0
// ensures: size() /= old size()-1
// return /= old front();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 53/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public:

It does not make sense


ringbuffer(); Postcondition:
to//tryensures:
and express the returned
size() /= 0
value
int from theconst;
size() history of pushes
and
const pops
T& as a post
top() condition.
const;
// requires: size() > 0 A guarantee from
const T& front() const; the implementation
// requires: size() > 0
void push_back(T t);
regarding the effect
// requires: size() < N of a legal call.
// ensures: size() /= old size()+1
// back() /= t
T pop_front();
// requires: size() > 0
// ensures: size() /= old size()-1
// return /= old front();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 54/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public:

ringbuffer(); Class invariant:


// ensures: size() /= 0
int size() const;
const T& back() const;
// ensures: size() > 0
const T& front() const;
// requires: size() > 0
void push_back(T t);
// requires: size() < N
// ensures: size() /= old size()+1
// back() /= t
T pop_front();
// requires: size() > 0
// ensures: size() /= old size()-1
// return /= old front();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 55/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public:

ringbuffer(); Class invariant:


// ensures: size() /= 0
int size() const;
const T& back() const;
Something that is
// ensures: size() > 0 always* true for a
const T& front() const; valid instance
// requires: size() > 0
void push_back(T t);
// requires: size() < N * outside public API
// ensures: size() /= old size()+1
// back() /= t
T pop_front();
// requires: size() > 0
// ensures: size() /= old size()-1
// return /= old front();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 56/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public:

ringbuffer(); Class invariant:


// ensures: size() /= 0 A class invariant
int size() const; always refers to state,
const T& back() const; and must be true even
Something that is
// ensures: size() > 0 when exceptions are always* true for a
const T& front() const; thrown. valid instance
// requires: size() > 0
void push_back(T t);
// requires: size() < N * outside public API
// ensures: size() /= old size()+1
// back() /= t
T pop_front();
// requires: size() > 0
// ensures: size() /= old size()-1
// return /= old front();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 57/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public:
// invariant: size() /= 0 /& size() /= N
ringbuffer(); Class invariant:
// ensures: size() /= 0
int size() const;
const T& back() const;
Something that is
// ensures: size() > 0 always* true for a
const T& front() const; valid instance
// requires: size() > 0
void push_back(T t);
// requires: size() < N * outside public API
// ensures: size() /= old size()+1
// back() /= t
T pop_front();
// requires: size() > 0
// ensures: size() /= old size()-1
// return /= old front();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 58/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public:
// invariant: size() /= 0 /& size() /= N
ringbuffer(); Class invariant:
// ensures: size() /= What
0 about a
int size() const; moved-from Something that is
const T& back() const; object?
// ensures: size() > 0 always* true for a
const T& front() const; valid instance
// requires: size() > 0
void push_back(T t);
// requires: size() < N * outside public API
// ensures: size() /= old size()+1
// back() /= t
T pop_front();
// requires: size() > 0
// ensures: size() /= old size()-1
// return /= old front();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 59/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public:
// invariant: size() /= 0 /& size() /= N
ringbuffer(); Contracts and
// ensures: size() /= 0 templates
int size() const;
const T& back() const;
// ensures: size() > 0
const T& front() const;
// requires: size() > 0
void push_back(T t);
// requires: size() < N
// ensures: size() /= old size()+1
// back() /= t
T pop_front();
// requires: size() > 0
// ensures: size() /= old size()-1
// return /= old front();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 60/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public:
// invariant: size() /= 0 /& size() /= N
ringbuffer(); Contracts and
// ensures: size() /= 0
What about templates
int size() const;
specializations?
const T& back() const;
// ensures: size() > 0
const T& front() const;
// requires: size() > 0
void push_back(T t);
// requires: size() < N
// ensures: size() /= old size()+1
// back() /= t
T pop_front();
// requires: size() > 0
// ensures: size() /= old size()-1
// return /= old front();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 61/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public: Contracts and
// invariant: size() /= 0 /& size() /= N
ringbuffer(); inheritance:
// ensures: size() /= 0
virtual int size() const = 0;
virtual const T& back() const = 0;
// requires: size() > 0
virtual const T& front() const = 0;
// requires: size() > 0
virtual void push_back(T t) = 0;
// requires: size() < N
// ensures: size() /= old size()+1
// back() /= t
virtual T pop_front() = 0;
// requires: size() > 0
// ensures: size() /= old size()-1
// return /= old front();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 62/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public: Contracts and
// invariant: size() /= 0 /& size() /= N
ringbuffer(); inheritance:
// ensures: size() /= 0
virtual int size() const = 0; A subcontractor
virtual const T& back() const = 0;
// requires: size() > 0 may have more
virtual const T& front() const = 0; relaxed pre-
// requires: size() > 0
virtual void push_back(T t) = 0;
conditions
// requires: size() < N
// ensures: size() /= old size()+1
// back() /= t
virtual T pop_front() = 0;
// requires: size() > 0
// ensures: size() /= old size()-1
// return /= old front();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 63/171
Ringbuffer example
template <typename T, int N>
class ringbuffer {
public: Contracts and
// invariant: size() /= 0 /& size() /= N
ringbuffer(); inheritance:
// ensures: size() /= 0
virtual int size() const = 0; A subcontractor
virtual const T& back() const = 0;
// requires: size() > 0 may have more
virtual const T& front() const = 0; relaxed pre-
// requires: size() > 0
virtual void push_back(T t) = 0;
conditions
// requires: size() < N
// ensures: size() /= old size()+1 and stricter post-
// back() /= t
virtual T pop_front() = 0;
conditions
// requires: size() > 0
// ensures: size() /= old size()-1
// return /= old front();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 64/171
Why bother?

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 65/171
Why bother?

1)It can make interfaces much clearer

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 66/171
Why bother?

1)It can make interfaces much clearer

2)It can make debugging much easier

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 67/171
Who dunnit?

guilty

client implementation

precondition

violation postcondition

invariant

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 68/171
Who dunnit?
Elementary,
Mr. Watson
guilty

client implementation

precondition

violation postcondition

invariant

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 69/171
Who dunnit?

guilty

client implementation

precondition

violation postcondition

invariant

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 70/171
Who dunnit?

guilty

client implementation

precondition

violation postcondition

invariant

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 71/171
Who dunnit?

guilty

client implementation

precondition

violation postcondition

invariant

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 72/171
Who dunnit?

guilty

client implementation

precondition

violation postcondition

invariant

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 73/171
Who dunnit?

guilty

client implementation

precondition

violation postcondition

invariant

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 74/171
Who dunnit?

guilty

client implementation

precondition

violation postcondition

invariant

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 75/171
Who dunnit?
Or you have
a bad contract!
guilty

client implementation

precondition

violation postcondition

invariant

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 76/171
Contracts in C++20

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 77/171
Contracts in C++20

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 78/171
Contracts in C++20

Description of
contract attribute
declarations and
semantics here
(4 pages)

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 79/171
Contracts in C++20

Description of
contract violation
handlers

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 80/171
Contracts in C++20

Meaning for
virtual functions
(1 paragraph)

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 81/171
Contracts in C++20

Contracts and
templates
(1 non-formative
sentence)

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 82/171
Contract attributes in C++20
9.11.4.1 Syntax [dcl.attr.contract.syn]
1# Contract attributes are used to specify preconditions, postconditions, and assertions for functions.

contract-attribute-specifier:
[ [ expects contract-levelopt : conditional-expression ] ]
[ [ ensures contract-levelopt identifieropt : conditional-expression ] ]
[ [ assert contract-levelopt : conditional-expression ] ]

contract-level:
default
audit
axiom
An ambiguity between a contract-level and an identifier is resolved in favor of contract-level.

http://eel.is/c/+draft/dcl.attr.contract#syn-1
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 83/171
Contract attributes in C++20
9.11.4.1 Syntax [dcl.attr.contract.syn]
1# Contract attributes are used to specify preconditions, postconditions, and assertions for functions.

contract-attribute-specifier:
[ [ expects contract-levelopt : conditional-expression ] ]
[ [ ensures contract-levelopt identifieropt : conditional-expression ] ]
[ [ assert contract-levelopt : conditional-expression ] ]

contract-level:
default Pre condition
audit
axiom
An ambiguity between a contract-level and an identifier is resolved in favor of contract-level.

http://eel.is/c/+draft/dcl.attr.contract#syn-1
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 84/171
Contract attributes in C++20
9.11.4.1 Syntax [dcl.attr.contract.syn]
1# Contract attributes are used to specify preconditions, postconditions, and assertions for functions.

contract-attribute-specifier:
[ [ expects contract-levelopt : conditional-expression ] ]
[ [ ensures contract-levelopt identifieropt : conditional-expression ] ]
[ [ assert contract-levelopt : conditional-expression ] ]

contract-level: template <typename T>


default Pre condition void func(std/:unique_ptr<T> p)
audit [[ expects : p /= nullptr ]];
axiom
An ambiguity between a contract-level and an identifier is resolved in favor of contract-level.

http://eel.is/c/+draft/dcl.attr.contract#syn-1
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 85/171
Contract attributes in C++20
9.11.4.1 Syntax [dcl.attr.contract.syn]
1# Contract attributes are used to specify preconditions, postconditions, and assertions for functions.

contract-attribute-specifier:
[ [ expects contract-levelopt : conditional-expression ] ]
[ [ ensures contract-levelopt identifieropt : conditional-expression ] ]
[ [ assert contract-levelopt : conditional-expression ] ]

contract-level: template <typename T>


default Optional level void func(std/:unique_ptr<T> p)
audit [[ expects : p /= nullptr ]];
axiom
An ambiguity between a contract-level and an identifier is resolved in favor of contract-level.

http://eel.is/c/+draft/dcl.attr.contract#syn-1
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 86/171
Contract attributes in C++20
9.11.4.1 Syntax [dcl.attr.contract.syn]
1# Contract attributes are used to specify preconditions, postconditions, and assertions for functions.

contract-attribute-specifier:
[ [ expects contract-levelopt : conditional-expression ] ]
[ [ ensures contract-levelopt identifieropt : conditional-expression ] ]
[ [ assert contract-levelopt : conditional-expression ] ]

contract-level: template <typename T>


default Optional level void func(std/:unique_ptr<T> p)
audit [[ expects axiom : p /= nullptr ]];
axiom
An ambiguity between a contract-level and an identifier is resolved in favor of contract-level.

http://eel.is/c/+draft/dcl.attr.contract#syn-1
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 87/171
Contract attributes in C++20
9.11.4.1 Syntax [dcl.attr.contract.syn]
1# Contract attributes are used to specify preconditions, postconditions, and assertions for functions.

contract-attribute-specifier:
[ [ expects contract-levelopt : conditional-expression ] ]
[ [ ensures contract-levelopt identifieropt : conditional-expression ] ]
[ [ assert contract-levelopt : conditional-expression ] ]

contract-level:
default Post condition
audit
axiom
An ambiguity between a contract-level and an identifier is resolved in favor of contract-level.

http://eel.is/c/+draft/dcl.attr.contract#syn-1
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 88/171
Contract attributes in C++20
9.11.4.1 Syntax [dcl.attr.contract.syn]
1# Contract attributes are used to specify preconditions, postconditions, and assertions for functions.

contract-attribute-specifier:
[ [ expects contract-levelopt : conditional-expression ] ]
[ [ ensures contract-levelopt identifieropt : conditional-expression ] ]
[ [ assert contract-levelopt : conditional-expression ] ]
template <typename T>
contract-level: T prev(T v)
default Post condition
[[ expects : v > 0 ]]
audit
[[ ensures audit r : r + 1 /= v ]];
axiom
An ambiguity between a contract-level and an identifier is resolved in favor of contract-level.

http://eel.is/c/+draft/dcl.attr.contract#syn-1
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 89/171
Contract attributes in C++20
9.11.4.1 Syntax [dcl.attr.contract.syn]
1# Contract attributes are used to specify preconditions, postconditions, and assertions for functions.
Name for
contract-attribute-specifier: return value
[ [ expects contract-levelopt : conditional-expression ] ] to use in
[ [ ensures contract-levelopt identifieropt : conditional-expression ] ] conditional
expression
[ [ assert contract-levelopt : conditional-expression ] ]
template <typename T>
contract-level: T prev(T v)
default Post condition
[[ expects : v > 0 ]]
audit
[[ ensures audit r : r + 1 /= v ]];
axiom
An ambiguity between a contract-level and an identifier is resolved in favor of contract-level.

http://eel.is/c/+draft/dcl.attr.contract#syn-1
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 90/171
Contract attributes in C++20
9.11.4.1 Syntax [dcl.attr.contract.syn]
1# Contract attributes are used to specify preconditions, postconditions, and assertions for functions.

contract-attribute-specifier:
[ [ expects contract-levelopt : conditional-expression ] ]
[ [ ensures contract-levelopt identifieropt : conditional-expression ] ]
[ [ assert contract-levelopt : conditional-expression ] ]

contract-level:
default Generic
audit assertion
axiom
An ambiguity between a contract-level and an identifier is resolved in favor of contract-level.

http://eel.is/c/+draft/dcl.attr.contract#syn-1
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 91/171
Contract attributes in C++20
9.11.4.1 Syntax [dcl.attr.contract.syn]
1# Contract attributes are used to specify preconditions, postconditions, and assertions for functions.

contract-attribute-specifier:
[ [ expects contract-levelopt : conditional-expression ] ]
[ [ ensures contract-levelopt identifieropt : conditional-expression ] ]
[ [ assert contract-levelopt : conditional-expression ] ]

contract-level: for (auto p : pointers) {


default Generic [[ assert axiom: p /= nullptr ]];
audit assertion func(p);
axiom }
An ambiguity between a contract-level and an identifier is resolved in favor of contract-level.

http://eel.is/c/+draft/dcl.attr.contract#syn-1
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 92/171
Contract attributes in C++20
9.11.4.1 Syntax [dcl.attr.contract.syn]
1# Contract attributes are usedThere are
to specify no
preconditions, postconditions, and assertions for functions.

contract-attribute-specifier: class invariants!


[ [ expects contract-levelopt : conditional-expression ] ]
[ [ ensures contract-levelopt identifieropt : conditional-expression ] ]
[ [ assert contract-levelopt : conditional-expression ] ]

contract-level:
default
audit
axiom
An ambiguity between a contract-level and an identifier is resolved in favor of contract-level.

http://eel.is/c/+draft/dcl.attr.contract#syn-1
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 93/171
Using C++20 contract attributes for ringbuffer
template <typename T, int N>
class ringbuffer {
public:
// invariant: size() /= 0 /& size() /= N
ringbuffer();
// ensures: size() /= 0
int size() const;
const T& back() const;
// requires: size() > 0
const T& front() const;
// requires: size() > 0
void push_back(T t);
// requires: size() < N
// ensures: size() /= old size()+1
// back() /= t
T pop_front();
// requires: size() > 0
// ensures: size() /= old size()-1
// return /= old front();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 94/171
Using C++20 contract attributes for ringbuffer
template <typename T, int N>
class ringbuffer {
public:
// invariant: size() /= 0 /& size() /= N
ringbuffer();
// ensures: size() /= 0
int size() const;
const T& back() const;
// requires: size() > 0
const T& front() const;
// requires: size() > 0
void push_back(T t);
// requires: size() < N
// ensures: size() /= old size()+1
// back() /= t
T pop_front();
// requires: size() > 0
// ensures: size() /= old size()-1
// return /= old front();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 95/171
Using C++20 contract attributes for ringbuffer
template <typename T, int N>
class ringbuffer {
public:
No support for
// invariant: size() /= 0 /& size() /= N class invariants,
ringbuffer(); so might as well
// ensures: size() /= 0 leave as comment.
int size() const;
const T& back() const;
// requires: size() > 0
const T& front() const;
// requires: size() > 0
void push_back(T t);
// requires: size() < N
// ensures: size() /= old size()+1
// back() /= t
T pop_front();
// requires: size() > 0
// ensures: size() /= old size()-1
// return /= old front();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 96/171
Using C++20 contract attributes for ringbuffer
template <typename T, int N>
class ringbuffer {
public:
// invariant: size() /= 0 /& size() /= N
ringbuffer();
// ensures: size() /= 0
int size() const;
const T& back() const;
// requires: size() > 0
const T& front() const;
// requires: size() > 0
void push_back(T t);
// requires: size() < N
// ensures: size() /= old size()+1
// back() /= t
T pop_front();
// requires: size() > 0
// ensures: size() /= old size()-1
// return /= old front();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 97/171
Using C++20 contract attributes for ringbuffer
template <typename T, int N>
class ringbuffer {
public:
// invariant: size() /= 0 /& size() /= N
ringbuffer()
[[ ensures: size() /= 0 ]];
int size() const;
const T& back() const;
// requires: size() > 0
const T& front() const;
// requires: size() > 0
void push_back(T t);
// requires: size() < N
// ensures: size() /= old size()+1
// back() /= t
T pop_front();
// requires: size() > 0
// ensures: size() /= old size()-1
// return /= old front();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 98/171
Using C++20 contract attributes for ringbuffer
template <typename T, int N>
class ringbuffer {
public:
// invariant: size() /= 0 /& size() < = N
ringbuffer()
[[ ensures: size() /= 0 ]];
int size() const;
const T& back() const;
// requires: size() > 0
const T& front() const;
<source>:6:15: error:
// requires: size() > 0 use of undeclared identifier 'size'
[[ push(T
void ensures:
t); size() /= 0 ]];
// requires: size() < N
// ensures: size() /= old size()+1
// back() /= t
T pop_front();
// requires: size() > 0
// ensures: size() /= old size()-1
// return /= old front();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 99/171
Using C++20 contractContract
attributes for ringbuffer
attributes are
template <typename T, int N>
class ringbuffer { declarations that can only
public: refer to identifiers seen
// invariant: size() /= 0 /& size() < =earlier.
N
ringbuffer()
[[ ensures: size() /= 0 ]];
int size() const;
const T& back() const;
// requires: size() > 0
const T& front() const;
<source>:6:15: error:
// requires: size() > 0 use of undeclared identifier 'size'
[[ push(T
void ensures:
t); size() /= 0 ]];
// requires: size() < N
// ensures: size() /= old size()+1
// back() /= t
T pop_front();
// requires: size() > 0
// ensures: size() /= old size()-1
// return /= old front();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 100/171
Using C++20 contractContract
attributes for ringbuffer
attributes are
template <typename T, int N>
class ringbuffer { declarations that can only
public: refer to identifiers seen
// invariant: size() /= 0 /& size() < =earlier.
N
int size() const;
ringbuffer()
[[ ensures: size() /= 0 ]];
const T& back() const;
// requires: size() > 0
const T& front() const;
// requires: size() > 0
void push_back(T t);
// requires: size() < N
// ensures: size() /= old size()+1
// back() /= t
T pop_front();
// requires: size() > 0
// ensures: size() /= old size()-1
// return /= old front();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 101/171
Using C++20 contract attributes for ringbuffer
template <typename T, int N>
class ringbuffer {
public:
// invariant: size() /= 0 /& size() /= N
int size() const;
ringbuffer()
[[ ensures: size() /= 0 ]];
const T& back() const;
// requires: size() > 0
const T& front() const;
// requires: size() > 0
void push_back(T t);
// requires: size() < N
// ensures: size() /= old size()+1
// back() /= t
T pop_front();
// requires: size() > 0
// ensures: size() /= old size()-1
// return /= old front();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 102/171
Using C++20 contract attributes for ringbuffer
template <typename T, int N>
class ringbuffer {
public:
// invariant: size() /= 0 /& size() /= N
int size() const;
ringbuffer()
[[ ensures: size() /= 0 ]];
const T& back() const
[[ expects: size() > 0 ]];
const T& front() const;
// requires: size() > 0
void push_back(T t);
// requires: size() < N
// ensures: size() /= old size()+1
// back() /= t
T pop_front();
// requires: size() > 0
// ensures: size() /= old size()-1
// return /= old front();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 103/171
Using C++20 contract attributes for ringbuffer
template <typename T, int N>
class ringbuffer {
public:
// invariant: size() /= 0 /& size() /= N
int size() const;
ringbuffer()
[[ ensures: size() /= 0 ]];
const T& back() const
[[ expects: size() > 0 ]];
const T& front() const;
// requires: size() > 0
void push_back(T t);
// requires: size() < N
// ensures: size() /= old size()+1
// back() /= t
T pop_front();
// requires: size() > 0
// ensures: size() /= old size()-1
// return /= old front();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 104/171
Using C++20 contract attributes for ringbuffer
template <typename T, int N>
class ringbuffer {
public:
// invariant: size() /= 0 /& size() /= N
int size() const;
ringbuffer()
[[ ensures: size() /= 0 ]];
const T& back() const
[[ expects: size() > 0 ]];
const T& front() const
[[ expects: size() > 0 ]];
void push_back(T t);
// requires: size() < N
// ensures: size() /= old size()+1
// back() /= t
T pop_front();
// requires: size() > 0
// ensures: size() /= old size()-1
// return /= old front();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 105/171
Using C++20 contract attributes for ringbuffer
template <typename T, int N>
class ringbuffer {
public:
// invariant: size() /= 0 /& size() /= N
int size() const;
ringbuffer()
[[ ensures: size() /= 0 ]];
const T& back() const
[[ expects: size() > 0 ]];
const T& front() const
[[ expects: size() > 0 ]];
void push_back(T t);
// requires: size() < N
// ensures: size() /= old size()+1
// back() /= t
T pop_front();
// requires: size() > 0
// ensures: size() /= old size()-1
// return /= old back();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 106/171
Using C++20 contract attributes for ringbuffer
template <typename T, int N>
class ringbuffer {
public:
// invariant: size() /= 0 /& size() /= N
int size() const;
ringbuffer()
[[ ensures: size() /= 0 ]];
const T& back() const
[[ expects: size() > 0 ]];
const T& front() const
[[ expects: size() > 0 ]];
void push_back(T t)
[[ expects: size() < N ]];
// ensures: size() /= old size()+1
// back() /= t
T pop_front();
// requires: size() > 0
// ensures: size() /= old size()-1
// return /= old back();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 107/171
Using C++20 contract attributes for ringbuffer
template <typename T, int N>
class ringbuffer {
public:
// invariant: size() /= 0 /& size() /= N
int size() const;
ringbuffer()
[[ ensures: size() /= 0 ]];
const T& back() const
[[ expects: size() > 0 ]];
const T& front() const
[[ expects: size() > 0 ]];
void push_back(T t)
[[ expects: size() < N ]];
// ensures: size() /= old size()+1
// back() /= t
T pop_front();
// requires: size() > 0
// ensures: size() /= old size()-1
// return /= old front();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 108/171
Using C++20 contract attributes for ringbuffer
template <typename T, int N>
class ringbuffer {
public: There is no way
// invariant: size() /= 0 /& size() /= N to refer to previous state
int size() const;
ringbuffer() so this cannot be
[[ ensures: size() /= 0 ]]; expressed!
const T& back() const
[[ expects: size() > 0 ]];
const T& front() const
[[ expects: size() > 0 ]];
void push_back(T t)
[[ expects: size() < N ]];
// ensures: size() /= old size()+1
// back() /= t
T pop_front();
// requires: size() > 0
// ensures: size() /= old size()-1
// return /= old front();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 109/171
Using C++20 contract attributes for ringbuffer
template <typename T, int N>
class ringbuffer {
public:
// invariant: size() /= 0 /& size() /= N
int size() const;
ringbuffer()
[[ ensures: size() /= 0 ]];
const T& back() const
[[ expects: size() > 0 ]];
const T& front() const
[[ expects: size() > 0 ]];
void push_back(T t)
[[ expects: size() < N ]]
[[ ensures: size() > 0 ]]; // incremented
// back() /= t
T pop_front();
// requires: size() > 0
// ensures: size() /= old size()-1
// return /= old front();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 110/171
Using C++20 contract attributes for ringbuffer
template <typename T, int N>
class ringbuffer {
public:
// invariant: size() /= 0 /& size() /= N
int size() const;
ringbuffer()
[[ ensures: size() /= 0 ]];
const T& back() const
[[ expects: size() > 0 ]];
const T& front() const
[[ expects: size() > 0 ]];
void push_back(T t)
[[ expects: size() < N ]];
[[ ensures: size() > 0 ]]; // incremented
// back() /= t
T pop_front();
// requires: size() > 0
// ensures: size() /= old size()-1
// return /= old front();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 111/171
Using C++20 contract attributes for ringbuffer
template <typename T, 6#
int IfN>a function has multiple preconditions, their evaluation (if any) will be
class ringbuffer { performed in the order they appear lexically. If a function has multiple
public: postconditions, their evaluation (if any) will be performed in the order they
// invariant: size()appear
/= 0lexically. [ Example:
/& size() /= N
int size() const;
ringbuffer() void f(int * p)
[[ ensures: size() /= [[expects:
0 ]]; p != nullptr]] // #1
const T& back() const [[ensures: *p == 1]] // #3
[[ expects: size() > 0[[expects:
]]; *p == 0]] // #2
const T& front() const
{
[[ expects: size() > 0*p ]];= 1;
void push_back(T t) }
[[ expects: size() <— end
N ]];example ]
[[ ensures: size() > 0 ]]; // incremented
// http://eel.is/c/+draft/dcl.attr.contract#cond-6
back() /= t
T pop_front();
// requires: size() > 0
// ensures: size() /= old size()-1
// return /= old front();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 112/171
Using C++20 contract attributes for ringbuffer
template <typename T, 6#
int IfN>a function has multiple preconditions, their evaluation (if any) will be
class ringbuffer { performed in the order they appear lexically. If a function has multiple
public: postconditions, their evaluation (if any) will be performed in the order they
// invariant: size()appear
/= 0lexically. [ Example:
/& size() /= N
int size() const;
ringbuffer() void f(int * p)
[[ ensures: size() /= [[expects:
0 ]]; p != nullptr]] // #1
const T& back() const [[ensures: *p == 1]] // #3
[[ expects: size() > 0[[expects:
]]; *p == 0]] // #2
const T& front() const
{
[[ expects: size() > 0*p ]];= 1;
void push_back(T t) }
[[ expects: size() <— end
N ]];example ]
[[ ensures: size() > 0 ]]; // incremented
// http://eel.is/c/+draft/dcl.attr.contract#cond-6
back() /= t
T pop_front();
// requires: size() > 0
// ensures: size() /= old size()-1
// return /= old front();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 113/171
Using C++20 contract attributes for ringbuffer
template <typename T, 7#
int IfN>a postcondition odr-uses ([basic.def.odr]) a parameter in its predicate
class ringbuffer { and the function body makes direct or indirect modifications of the value of
public: that parameter, the behavior is undefined. [ Example:
// invariant: size()int
/= 0 /& size()
f(int x) /= N
int size() const; [[ensures r: r == x]]
ringbuffer() {
[[ ensures: size() /= return
0 ]]; ++x; // undefined behavior
const T& back() const
}
[[ expects: size() > 0 ]];
const T& front() const
...
[[ expects: size() > 0 ]];
void push_back(T t) http://eel.is/c/+draft/dcl.attr.contract#cond-7
[[ expects: size() < N ]]
[[ ensures: size() > 0 ]]; // incremented
// back() /= t
T pop_front();
// requires: size() > 0
// ensures: size() /= old size()-1
// return /= old front();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 114/171
Using C++20 contract attributes for ringbuffer
template <typename T, 7#
int IfN>a postcondition odr-uses ([basic.def.odr]) a parameter in its predicate
class ringbuffer { and the function body makes direct or indirect modifications of the value of
public: that parameter, the behavior is undefined. [ Example:
// invariant: size()int
/= 0 /& size() /= N
int size() const;
f(int x)
[[ensures r: r == x]]
So the validity
ringbuffer() { of the post condition
[[ ensures: size() /= return
0 ]]; ++x;
const T& back() const
}
declaration depends on
// undefined behavior
[[ expects: size() > 0 ]]; how the function is
const T& front() const
...
[[ expects: size() > 0 ]]; implemented
void push_back(T t) http://eel.is/c/+draft/dcl.attr.contract#cond-7
[[ expects: size() < N ]]
[[ ensures: size() > 0 ]]; // incremented
// back() /= t
T pop_front();
// requires: size() > 0
// ensures: size() /= old size()-1
// return /= old front();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 115/171
Using C++20 contract attributes for ringbuffer
template <typename T, int N>
class ringbuffer {
public:
// invariant: size() /= 0 /& size() /= N
int size() const;
ringbuffer() Potentially
[[ ensures: size() /= 0 ]];
const T& back() const dangerous
[[ expects: size() > 0 ]];
const T& front() const
[[ expects: size() > 0 ]];
void push_back(T t)
[[ expects: size() < N ]]
[[ ensures: size() > 0 ]] // incremented
[[ ensures: back() /= t ]];
T pop_front();
// requires: size() > 0
// ensures: size() /= old size()-1
// return /= old front();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 116/171
Using C++20 contract attributes for ringbuffer
template <typename T, int N>
class ringbuffer {
public:
// invariant: size() /= 0 /& size() /= N
int size() const;
ringbuffer()
[[ ensures: size() /= 0 ]];
const T& back() const
[[ expects: size() > 0 ]];
const T& front() const
[[ expects: size() > 0 ]];
void push_back(T t)
[[ expects: size() < N ]]
[[ ensures: size() > 0 ]] // incremented
[[ ensures: back() /= t ]];
T pop_front();
// requires: size() > 0
// ensures: size() /= old size()-1
// return /= old front();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 117/171
Using C++20 contract attributes for ringbuffer
template <typename T, int N>
class ringbuffer {
public:
// invariant: size() /= 0 /& size() /= N
int size() const;
ringbuffer()
[[ ensures: size() /= 0 ]];
const T& back() const
[[ expects: size() > 0 ]];
const T& front() const
[[ expects: size() > 0 ]];
void push_back(T t)
[[ expects: size() < N ]]
[[ ensures: size() > 0 ]] // incremented
[[ ensures: back() /= t ]];
T pop_front()
[[ expects: size() > 0 ]];
// ensures: size() /= old size()-1
// return /= old front();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 118/171
Using C++20 contract attributes for ringbuffer
template <typename T, int N>
class ringbuffer {
public:
// invariant: size() /= 0 /& size() /= N
int size() const;
ringbuffer()
[[ ensures: size() /= 0 ]];
const T& back() const
[[ expects: size() > 0 ]];
const T& front() const
[[ expects: size() > 0 ]];
void push_back(T t)
[[ expects: size() < N ]]
[[ ensures: size() > 0 ]] // incremented
[[ ensures: back() /= t ]];
T pop_front()
[[ expects: size() > 0 ]];
// ensures: size() /= old size()-1
// return /= old front();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 119/171
Using C++20 contract attributes for ringbuffer
template <typename T, int N>
class ringbuffer {
public:
// invariant: size() /= 0 /& size() /= N
int size() const;
ringbuffer()
[[ ensures: size() /= 0 ]];
const T& back() const
[[ expects: size() > 0 ]];
const T& front() const
[[ expects: size() > 0 ]];
void push_back(T t)
[[ expects: size() < N ]]
[[ ensures: size() > 0 ]] // incremented
[[ ensures: back() /= t ]];
T pop_front()
[[ expects: size() > 0 ]]
[[ ensures: size() < N ]]; // decremented
// return /= old front();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 120/171
Using C++20 contract attributes for ringbuffer
template <typename T, int N>
class ringbuffer {
public:
// invariant: size() /= 0 /& size() /= N
int size() const;
ringbuffer()
[[ ensures: size() /= 0 ]]; Cannot express
const T& back() const
[[ expects: size() > 0 ]]; condition with
const T& front() const previous state so
[[ expects: size() > 0 ]];
void push_back(T t)
might as well leave
[[ expects: size() < N ]] as comment
[[ ensures: size() > 0 ]] // incremented
[[ ensures: back() /= t ]];
T pop_front()
[[ expects: size() > 0 ]]
[[ ensures: size() < N ]]; // decremented
// return /= old front();
};
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 121/171
Virtual functions and contracts in C++20

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 122/171
Virtual functions and contracts in C++20

If an overriding function specifies contract conditions ([dcl.attr.contract]), it shall


specify the same list of contract conditions as its overridden functions; no
diagnostic is required if corresponding conditions will always evaluate to the
same value. Otherwise, it is considered to have the list of contract conditions
from one of its overridden functions; ...

http://eel.is/c/+draft/class.virtual#19

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 123/171
Virtual functions and contracts in C++20

If an overriding function specifies contract conditions ([dcl.attr.contract]), it shall


specify the same list of contract conditions as its overridden functions; no
diagnostic is required if corresponding conditions will always evaluate to the
same value. Otherwise, it is considered to have the list of contract conditions
from one of its overridden functions; ...

http://eel.is/c/+draft/class.virtual#19

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 124/171
Virtual functions and contracts in C++20

If an overriding function specifies contract conditions ([dcl.attr.contract]), it shall


specify the same list of contract conditions as its overridden functions; no
diagnostic is required if corresponding conditions will always evaluate to the
same value. Otherwise, it is considered to have the list of contract conditions
from one of its overridden functions; ...

http://eel.is/c/+draft/class.virtual#19

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 125/171
Function pointers and contracts in C++20

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 126/171
Function pointers and contracts in C++20

3 #[ Note: A function pointer cannot include contract conditions. [ Example:


typedef int (*fpt)(int) [[ensures r: r /= 0]];
// error: contract condition not on a function declaration
int g(int x) [[expects: x /= 0]] [[ensures r: r > x]]
{
return x+1;
}

int (*pf)(int) = g; // OK
int x = pf(5); // contract conditions of g are checked

— end example ] — end note ]


http://eel.is/c/+draft/dcl.attr.contract#cond-3

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 127/171
Function pointers and contracts in C++20

3 #[ Note: A function pointer cannot include contract conditions. [ Example:


typedef int (*fpt)(int) [[ensures r: r /= 0]];
// error: contract condition not on a function declaration
int g(int x) [[expects: x /= 0]] [[ensures r: r > x]] In other words, it is
{
the responsibility of a function
return x+1;
implementation to enforce its
}
contracts, not the caller.
int (*pf)(int) = g; // OK
int x = pf(5); // contract conditions of g are checked

— end example ] — end note ]


http://eel.is/c/+draft/dcl.attr.contract#cond-3

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 128/171
Let’s explore!

https://github.com/arcosuc3m/clang-contracts

Fork from clang-6

http://fragata.arcos.inf.uc3m.es/#

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 129/171
Function pointers and contracts in C++20

3 #[ Note: A function
P1320R1 pointer
Allowing cannot
contract include
predicates contractdeclarations
on non-first conditions. [ Example:
typedef int (*fpt)(int) [[ensures r: r /= 0]];
Ville Voutilainen
// error: contract condition not on a function declaration
int g(int struct
x) [[expects:
X { x /= 0]] [[ensures r: r > x]]
{
void f();
return x+1;
} };

void X/:f()
int (*pf)(int) = g; [[expects: foo]]
// OK
{
int x = pf(5); // contract conditions of g are checked
//.
— end example ]
} — end note ]
http://eel.is/c/+draft/dcl.attr.contract#cond-3

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 130/171
Policing contracts in C++20

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 131/171
Policing contracts in C++20

3# A translation may be performed with one of the following build levels: off,
default, or audit. A translation with build level set to off performs no checking
for any contract. A translation with build level set to default performs checking
for default contracts. A translation with build level set to audit performs
checking for default and audit contracts. If no build level is explicitly selected,
the build level is default. The mechanism for selecting the build level is
implementation-defined. The translation of a program consisting of translation
units where the build level is not the same in all translation units is conditionally-
supported. There should be no programmatic way of setting, modifying, or
querying the build level of a translation unit.
http://eel.is/c/+draft/dcl.attr.contract#check-3

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 132/171
Policing contracts in C++20

3# A translation may be performed with one of the following build levels: off,
default, or audit. A translation with build level set to off performs no checking
for any contract. A translation with build level set to default performs checking
for default contracts. A translation with build level set to audit performs
checking for default and audit contracts. If no build level is explicitly selected,
the build level is default. The mechanism for selecting the build level is
implementation-defined. The translation of a program consisting of translation
units where the build level is not the same in all translation units is conditionally-
supported. There should be no programmatic way of setting, modifying, or
querying the build level of a translation unit.
http://eel.is/c/+draft/dcl.attr.contract#check-3

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 133/171
Policing contracts in C++20

3# A translation may be performed with one of the following build levels: off,
default, or audit. A translation with build level set to off performs no checking
for any contract. A translation with build level set to default performs checking
for default contracts. A translation with build level set to audit performs
checking for default and audit contracts. If no build level is explicitly selected,
the build level is default. The mechanism for selecting the build level is
implementation-defined. The translation of a program consisting of translation
units where the build level is not the same in all translation units is conditionally-
supported. There should be no programmatic way of setting, modifying, or
querying the build level of a translation unit.
http://eel.is/c/+draft/dcl.attr.contract#check-3

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 134/171
Policing contracts in C++20

3# A translation may be performed with one of the following build levels: off,
default, or audit. A translation with build level set to off performs no checking
for any contract. A translation with build level set to default performs checking
for default contracts. A translation with build level set to audit performs
checking for default and audit contracts. If no build level is explicitly selected,
the build level is default. The mechanism for selecting the build level is
implementation-defined. The translation of a program consisting of translation
units where the build level is not the same in all translation units is conditionally-
supported. There should be no programmatic way of setting, modifying, or
querying the build level of a translation unit.
http://eel.is/c/+draft/dcl.attr.contract#check-3

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 135/171
Policing contracts in C++20

3# A translation may be performed with one of the following build levels: off,
default, or audit. A translation with build level set to off performs no checking
for any contract. A translation with build level set to default performs checking
for default contracts. A translation with build level set to audit performs
checking for default and audit contracts. If no build level is explicitly selected,
the build level is default. The mechanism for selecting the build level is
implementation-defined. The translation of a program consisting of translation
units where the build level is not the same in all translation units is conditionally-
supported. There should be no programmatic way of setting, modifying, or
querying the build level of a translation unit.
http://eel.is/c/+draft/dcl.attr.contract#check-3

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 136/171
Policing contracts in C++20

3# A translation may be performed with one of the following build levels: off,
default, or audit. A translation with build level set to off performs no checking
P1421r0 Assigning
for any contract. semantics
A translation withtobuild
different
levelContract Checking
set to default Statements
performs checking
for default contracts.
Andrzej Krzemieński
A translation with build level set to audit performs
checking for default and audit contracts. If no build level is explicitly selected,
the buildAllowing
level is different
default.levels
The mechanism for of
for different types selecting
contracts,the
e.g.build level is
audit on
preconditions, and off
implementation-defined. Theon translation
the others. of a program consisting of translation
units where the build level is not the same in all translation units is conditionally-
supported. There should be no programmatic way of setting, modifying, or
querying the build level of a translation unit.
http://eel.is/c/+draft/dcl.attr.contract#check-3

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 137/171
Policing contracts in C++20

3# A translation may be performed with one of the following build levels: off,
default, or audit. A translation with build level set to off performs no checking
for any contract. A translation with build level set to default performs checking
for default contracts. A translation with build level set to audit performs
checking for default and audit contracts. If no build level is explicitly selected,
the build level is default. The mechanism for selecting the build level is
implementation-defined. The translation of a program consisting of translation
units where the build level is not the same in all translation units is conditionally-
supported. There should be no programmatic way of setting, modifying, or
querying the build level of a translation unit.
http://eel.is/c/+draft/dcl.attr.contract#check-3

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 138/171
Policing contracts in C++20

3# A translation may be performed with one of the following build levels: off,
default, or audit. A translation with build level set to off performs no checking
for any contract. A translation with build level set to default performs checking
for default contracts. A translation with build level set to audit performs
checking for default and audit contracts. If no build level is explicitly selected,
the build level is default. The mechanism for selecting the build level is
implementation-defined. The translation of a program consisting of translation
units where the build level is not the same in all translation units is conditionally-
supported. There should be no programmatic way of setting, modifying, or
querying the build level of a translation unit.
http://eel.is/c/+draft/dcl.attr.contract#check-3

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 139/171
Policing contracts in C++20

3# A translation
3.7 may be performed with one of[defns.cond.supp]
the following build levels: off,
default, orconditionally-supported
audit. A translation with build level set to off performs no checking
programA
for any contract. construct that anwith
translation implementation
build levelis set
not required to support
to default performs checking
[ Note: Each implementation documents all conditionally-supported
for defaultconstructs
contracts. A translation with build level set to audit performs
that it does not support. — end note ]
checking for default and audit contracts. If no build level is explicitly selected,
http://eel.is/c/+draft/intro.defs#defns.cond.supp
the build level is default. The mechanism for selecting the build level is
implementation-defined. The translation of a program consisting of translation
units where the build level is not the same in all translation units is conditionally-
supported. There should be no programmatic way of setting, modifying, or
querying the build level of a translation unit.
http://eel.is/c/+draft/dcl.attr.contract#check-3

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 140/171
Policing contracts in C++20

3# A translation may be performed with one of the following build levels: off,
default, or audit. A translation with build level set to off performs no checking
for any contract. A translation with build level set to default performs checking
for default contracts. A translation with build level set to audit performs
checking for default and audit contracts. If no build level is explicitly selected,
the build level is default. The mechanism for selecting the build level is
implementation-defined. The translation of a program consisting of translation
units where the build level is not the same in all translation units is conditionally-
supported. There should be no programmatic way of setting, modifying, or
querying the build level of a translation unit.
http://eel.is/c/+draft/dcl.attr.contract#check-3

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 141/171
Let’s explore!

https://github.com/arcosuc3m/clang-contracts

Fork from clang-6

http://fragata.arcos.inf.uc3m.es/#

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 142/171
Let’s explore!

https://github.com/arcosuc3m/clang-contracts

Fork from clang-6

http://fragata.arcos.inf.uc3m.es/#

-build-level=(off|default|audit)

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 143/171
When contracts are violated in C++20

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 144/171
When contracts are violated in C++20
5# The violation handler of a program is a function of type “noexceptopt function
of (lvalue reference to const std/:contract_violation) returning void”. The
violation handler is invoked when the predicate of a checked contract evaluates
to false (called a contract violation). There should be no programmatic way of
setting or modifying the violation handler. It is implementation-defined how the
violation handler is established for a program and how the
std/:contract_violation argument value is set, except as specified below. If a
precondition is violated, the source location of the violation is implementation-
defined. [ Note: Implementations are encouraged but not required to report the
caller site. — end note ] If a postcondition is violated, the source location of the
violation is the source location of the function definition. If an assertion is
violated, the source location of the violation is the source location of the
statement to which the assertion is applied.
http://eel.is/c/+draft/dcl.attr.contract#check-5
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 145/171
When contracts are violated in C++20
5# The violation handler of a program is a function of type “noexceptopt function
of (lvalue reference to const std/:contract_violation) returning void”. The
violation handler is invoked when the predicate of a checked contract evaluates
to false (called a contract violation). There should be no programmatic way of
setting or modifying the violation handler. It is implementation-defined how the
violation handler is established for a program and how the
std/:contract_violation argument value is set, except as specified below. If a
precondition is violated, the source location of the violation is implementation-
defined. [ Note: Implementations are encouraged but not required to report the
caller site. — end note ] If a postcondition is violated, the source location of the
violation is the source location of the function definition. If an assertion is
violated, the source location of the violation is the source location of the
statement to which the assertion is applied.
http://eel.is/c/+draft/dcl.attr.contract#check-5
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 146/171
When contracts are violated in C++20
5# The violation handler of a program is a function of type “noexceptopt function
of (lvalue reference to const std/:contract_violation) returning void”. The
violation handler
16.8.2 isClass
invoked when
contract_ the predicate[support.contract.cviol]
violation of a checked contract evaluates
to false (called a contract
namespace stdviolation).
{ There should be no programmatic way of
setting or modifying the violation handler. It{ is implementation-defined how the
class contract_violation
violation handler is established for a program and how the
public:
std/:contract_ uint_least32_t
violation argument line_number()
value is set, const
except noexcept;
as specified below. If a
precondition is string_view file_name()
violated, the source const
location of noexcept;
the violation is implementation-
defined. [ Note:string_view
Implementations function_name() const noexcept;
are encouraged but not required to report the
string_view comment() const noexcept;
caller site. — end note ] If a postcondition is violated, the source location of the
string_view assertion_level() const noexcept;
violation is the
}; source location of the function definition. If an assertion is
violated, the
} source location of the violation is the source location of the
statement to which the assertion is applied.
http://eel.is/c/+draft/support.contract.cviol
http://eel.is/c/+draft/dcl.attr.contract#check-5
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 147/171
When contracts are violated in C++20
5# The violation handler of a program is a function of type “noexceptopt function
of (lvalue reference to const std/:contract_violation) returning void”. The
violation handler is invoked when the predicate of a checked contract evaluates
to false (called a contract violation). There should be no programmatic way of
setting or modifying the violation handler. It is implementation-defined how the
violation handler is established for a program and how the
std/:contract_violation argument value is set, except as specified below. If a
precondition is violated, the source location of the violation is implementation-
defined. [ Note: Implementations are encouraged but not required to report the
caller site. — end note ] If a postcondition is violated, the source location of the
violation is the source location of the function definition. If an assertion is
violated, the source location of the violation is the source location of the
statement to which the assertion is applied.
http://eel.is/c/+draft/dcl.attr.contract#check-5
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 148/171
When contracts are violated in C++20
5# The violation handler of a program is a function of type “noexceptopt function
of (lvalue reference to const std/:contract_violation) returning void”. The
violation handler is invoked when the predicate of a checked contract evaluates
to false (called a contract violation). There should be no programmatic way of
setting or modifying the violation handler. It is implementation-defined how the
violation handler is established for a program and how the
std/:contract_violation argument value is set, except as specified below. If a
precondition is violated, the source location of the violation is implementation-
defined. [ Note: Implementations are encouraged but not required to report the
caller site. — end note ] If a postcondition is violated, the source location of the
violation is the source location of the function definition. If an assertion is
violated, the source location of the violation is the source location of the
statement to which the assertion is applied.
http://eel.is/c/+draft/dcl.attr.contract#check-5
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 149/171
When contracts are violated in C++20
5# The violation handler of a program is a function of type “noexceptopt function
of (lvalue reference to const std/:contract_violation) returning void”. The
violation handler is invoked when the predicate of a checked contract evaluates
to false (called a contract violation). There should be no programmatic way of
setting or modifying the violation handler. It is implementation-defined how the
violation handler is established for a program and how the
std/:contract_violation argument value is set, except as specified below. If a
precondition is violated, the source location of the violation is implementation-
defined. [ Note: Implementations are encouraged but not required to report the
caller site. — end note ] If a postcondition is violated, the source location of the
violation is the source location of the function definition. If an assertion is
violated, the source location of the violation is the source location of the
statement to which the assertion is applied.
http://eel.is/c/+draft/dcl.attr.contract#check-5
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 150/171
Let’s explore!

https://github.com/arcosuc3m/clang-contracts

Fork from clang-6

http://fragata.arcos.inf.uc3m.es/#

-build-level=(off|default|audit)

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 151/171
Let’s explore!

https://github.com/arcosuc3m/clang-contracts

Fork from clang-6

http://fragata.arcos.inf.uc3m.es/#

-build-level=(off|default|audit)

-contract-violation-handler=function

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 152/171
When contracts are violated in C++20

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 153/171
When contracts are violated in C++20
A translation may be performed with one of the following violation
continuation modes: off or on. A translation with violation continuation
mode set to off terminates execution by invoking the function
std/:terminate ([except.terminate]) after completing the execution of
the violation handler. A translation with a violation continuation mode set
to on continues execution after completing the execution of the violation
handler. If no continuation mode is explicitly selected, the default
continuation mode is off. [ Note: A continuation mode set to on provides
the opportunity to install a logging handler to instrument a pre-existing
code base and fix errors before enforcing checks. — end note ]

http://eel.is/c/+draft/dcl.attr.contract#check-7
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 154/171
When contracts are violated in C++20
A translation may be performed with one of the following violation
continuation modes: off or on. A translation with violation continuation
mode set to off terminates execution by invoking the function
std/:terminate ([except.terminate]) after completing the execution of
the violation handler. A translation with a violation continuation mode set
to on continues execution after completing the execution of the violation
handler. If no continuation mode is explicitly selected, the default
continuation mode is off. [ Note: A continuation mode set to on provides
the opportunity to install a logging handler to instrument a pre-existing
code base and fix errors before enforcing checks. — end note ]

http://eel.is/c/+draft/dcl.attr.contract#check-7
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 155/171
When contracts are violated in C++20
A translation may be performed with one of the following violation
continuation modes: off or on. A translation with violation continuation
mode set to off terminates execution by invoking the function
std/:terminate ([except.terminate]) after completing the execution of
the violation handler. A translation with a violation continuation mode set
to on continues execution after completing the execution of the violation
handler. If no continuation mode is explicitly selected, the default
continuation mode is off. [ Note: A continuation mode set to on provides
the opportunity to install a logging handler to instrument a pre-existing
code base and fix errors before enforcing checks. — end note ]

http://eel.is/c/+draft/dcl.attr.contract#check-7
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 156/171
When contracts are violated in C++20
A translation may be performed with one of the following violation
continuation modes: off or on. A translation with violation continuation
mode set to off terminates execution by invoking the function
std/:terminate ([except.terminate]) after completing the execution of
the violation handler. A translation with a violation continuation mode set
to on continues execution after completing the execution of the violation
handler. If no continuation mode is explicitly selected, the default
continuation mode is off. [ Note: A continuation mode set to on provides
the opportunity to install a logging handler to instrument a pre-existing
code base and fix errors before enforcing checks. — end note ]

http://eel.is/c/+draft/dcl.attr.contract#check-7
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 157/171
When contracts are violated in C++20
A translation may be performed with one of the following violation
continuation modes: off or on. A translation with violation continuation
mode set to off terminates execution by invoking the function
[ Example:
std/:terminate
void f(int([except.terminate])
x) [[expects: x >after 0]]; completing the execution of
the violation handler. A translation with a violation continuation mode set
to on continues
void g()execution
{ after completing the execution of the violation
handler. If no continuation
f(0); // std/: mode is explicitly
terminate() selected,
after theif
handler default
continuation mode is //off.
continuation mode is off;
[ Note: A continuation mode set to on provides
// proceeds
the opportunity to install a loggingafter handler
handler if
to instrument a pre-existing
// continuation mode is on
code base and fix errors before enforcing checks. — end note ]
/* //. //
}
— end example ]

http://eel.is/c/+draft/dcl.attr.contract#check-7
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 158/171
When contracts are violated in C++20
A translation may be performed with one of the following violation
continuation modes: off or on. A translation with violation continuation
mode set to off terminates execution by invoking the function
std/:terminate ([except.terminate]) after completing the execution of
the violation handler.
P1429r0 A translation
- Contracts that work with a violation continuation mode set
to on continues execution after completing the execution of the violation
handler. IfJoshua
no continuation mode is explicitly selected, the default
Bern, John Lakos
continuation mode is off. [ Note: A continuation mode set to on provides
Distinguishing between violations that can be safely continued from,
the opportunity to install
and violations that a
arelogging
fatal. handler to instrument a pre-existing
code base and fix errors before enforcing checks. — end note ]

http://eel.is/c/+draft/dcl.attr.contract#check-7
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 159/171
Programming with Contracts in C++20

Björn Fahller

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 160/171
Summary


Design by contract is a way to clarify the responsibility between a
function implementation and its callers.

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 161/171
Summary


Design by contract is a way to clarify the responsibility between a
function implementation and its callers.

Language support is coming in C++20

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 162/171
Summary


Design by contract is a way to clarify the responsibility between a
function implementation and its callers.

Language support is coming in C++20

But it’s lacking class invariants

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 163/171
Summary


Design by contract is a way to clarify the responsibility between a
function implementation and its callers.

Language support is coming in C++20

But it’s lacking class invariants

and post conditions cannot refer to pre-call state.

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 164/171
Summary


Design by contract is a way to clarify the responsibility between a
function implementation and its callers.

Language support is coming in C++20

But it’s lacking class invariants

and post conditions cannot refer to pre-call state.

Interesting gotchas:

Modifying parameter values, and template specializations comes to
mind.

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 165/171
Summary


Design by contract is a way to clarify the responsibility between a
function implementation and its callers.

Language support is coming in C++20

But it’s lacking class invariants

and post conditions cannot refer to pre-call state.

Interesting gotchas:

Modifying parameter values, and template specializations comes to
mind.

Contracts can be used by static analysis tools and the optimizer.

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 166/171
Summary


Design by contract is a way to clarify the responsibility between a
function implementation and its callers.

Language support is coming in C++20

But it’s lacking class invariants

and post conditions cannot refer to pre-call state.

Interesting gotchas:

Modifying parameter values, and template specializations comes to
mind.

Contracts can be used by static analysis tools and the optimizer.

Configurable levels of contracts, e.g. full in debug builds, only cheap
ones in release.

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 167/171
Summary


Design by contract is a way to clarify the responsibility between a
function implementation and its callers.

Language support is coming in C++20

But it’s lackingP1426r0 Pull the Plug on Contracts?
class invariants

and post conditions cannot refer to pre-call state.
Nathan Meyers.

Interesting gotchas:
● Argues that values,
Modifying parameter the whole idea
andgot wrong andspecializations
template should comes to
be scrapped and replaced with something else.
mind.

Contracts can be used by static analysis tools and the optimizer.

Configurable levels of contracts, e.g. full in debug builds, only cheap
ones in release.

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 168/171
Summary


Design by contract is a way to clarify the responsibility between a
function implementation and its callers.

Language support is coming in C++20

But it’s lacking class invariants

and post conditions cannot refer to pre-call state.

Interesting gotchas:

Modifying parameter values, and template specializations comes to
mind.

Contracts can be used by static analysis tools and the optimizer.

Configurable levels of contracts, e.g. full in debug builds, only cheap
ones in release.

Prefer to express semantics using the type system, if you can.
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 169/171
Summary


Design by contract is a wayPlayto clarify
with theit!
responsibility between a
function implementation and its callers.

Language support is coming in C++20

But it’s lacking class invariants
https://github.com/arcosuc3m/clang-contracts

and post conditions cannot refer to pre-call state.

Interesting gotchas: Fork from clang-6

Modifying parameter values, and template specializations comes to
mind. http://fragata.arcos.inf.uc3m.es/#

Contracts can be used by static analysis tools and the optimizer.

Configurable levels of contracts, e.g. full in debug builds, only cheap
ones in release.

Prefer to express semantics using the type system, if you can.
Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 170/171
Programming with Contracts in C++20

Björn Fahller

bjorn@fahller.se

@bjorn_fahller

@rollbear

Programming with Contracts in C++20 – C++onSea 2019 © Björn Fahller @bjorn_fahller 171/171

You might also like