Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ACCU2019 - Programming with Contracts in C++20

ACCU2019 - Programming with Contracts in C++20

Design by Contract is a technique to clearly express which parts of a program has which responsibilities. In the case of bugs, contracts can mercilessly point a finger at the part that violated the contract.

Contracts are coming as a language feature in C++20. I will show how they can make your interfaces clearer with regards to use, but also point out pitfalls and oddities in how contracts are handled in C++.

Writing good contracts can be difficult. I intend to give you guidance in how to think when formulating contracts, and how to design your interfaces such that good contracts can be written, because contracts have effects on interface design.

Warning: Parts of the contents are personal opinion.

5d138ccf47c8d79aa8f0d29900f9e07b?s=128

Björn Fahller

April 12, 2019
Tweet

Transcript

  1. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 1/168 Programming with Contracts in C++20 Björn Fahller
  2. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 2/168 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
  3. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 3/168 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 In SW design: A formalised agreement, regarding program correctness, between a user and the implementation of a component.
  4. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 4/168 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 In SW design: A formalised agreement, regarding program correctness, between a user and the implementation of a component.
  5. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 5/168 Contracts • Object-oriented Software Construction – Bertrand Meyer - 1988 – ISBN 978-0136290490
  6. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 6/168 • Preconditions • Postconditions • Class invariants Contracts
  7. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 7/168 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);
  8. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 8/168 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);
  9. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 9/168 Ringbuffer example 1 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);
  10. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 10/168 Ringbuffer example 1 2 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);
  11. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 11/168 Ringbuffer example 1 2 5 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);
  12. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 12/168 Ringbuffer example 1 2 5 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);
  13. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 13/168 Ringbuffer example 2 5 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);
  14. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 14/168 Ringbuffer example 2 5 8 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);
  15. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 15/168 Ringbuffer example 2 5 8 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);
  16. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 16/168 Ringbuffer example 5 8 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);
  17. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 17/168 Ringbuffer example 5 8 11 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);
  18. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 18/168 Ringbuffer example 5 8 11 13 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);
  19. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 19/168 Ringbuffer example 5 8 11 13 15 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);
  20. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 20/168 Ringbuffer example 5 8 11 13 15 21 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);
  21. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 21/168 Ringbuffer example 5 8 11 13 15 21 23 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);
  22. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 22/168 Ringbuffer example 5 8 11 13 15 21 23 24 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);
  23. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 23/168 Ringbuffer example template <typename T, int N> class ringbuffer { public: ringbuffer(); int size() const; void push_back(T); T pop_front(); };
  24. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 24/168 Ringbuffer example template <typename T, int N> class ringbuffer { public: ringbuffer(); int size() const; void push_back(T); T pop_front(); }; Precondition:
  25. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 25/168 Ringbuffer example template <typename T, int N> class ringbuffer { public: ringbuffer(); int size() const; void push_back(T); T pop_front(); }; Precondition: An obligation that the caller must fulfill for the program to be correct.
  26. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 26/168 Ringbuffer example template <typename T, int N> class ringbuffer { public: ringbuffer(); int size() const; void push_back(T); T pop_front(); }; Precondition: An obligation that the caller must fulfill for the program to be correct. A precondition may refer to parameter values or the objects state, or both
  27. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 27/168 Ringbuffer example template <typename T, int N> class ringbuffer { public: ringbuffer(); int size() const; void push_back(T); T pop_front(); }; Precondition: An obligation that the caller must fulfill for the program to be correct.
  28. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 28/168 Ringbuffer example template <typename T, int N> class ringbuffer { public: ringbuffer(); int size() const; void push_back(T); T pop_front(); }; Precondition: An obligation that the caller must fulfill for the program to be correct. It almost never makes sense to have a precondition on a default constructor!
  29. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 29/168 Ringbuffer example template <typename T, int N> class ringbuffer { public: ringbuffer(); int size() const; void push_back(T); T pop_front(); }; Precondition: An obligation that the caller must fulfill for the program to be correct.
  30. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 30/168 Ringbuffer example template <typename T, int N> class ringbuffer { public: ringbuffer(); int size() const; void push_back(T); T pop_front(); }; Precondition: An obligation that the caller must fulfill for the program to be correct. Functions that query the state of an object rarely has any preconditions.
  31. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 31/168 Ringbuffer example template <typename T, int N> class ringbuffer { public: ringbuffer(); int size() const; void push_back(T); T pop_front(); }; Precondition: An obligation that the caller must fulfill for the program to be correct.
  32. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 32/168 Ringbuffer example template <typename T, int N> class ringbuffer { public: ringbuffer(); int size() const; void push_back(T); T pop_front(); }; Precondition: An obligation that the caller must fulfill for the program to be correct. Choose between: Define behaviour when full, or make not-full a precondition.
  33. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 33/168 Ringbuffer example template <typename T, int N> class ringbuffer { public: ringbuffer(); int size() const; void push_back(T); // requires: size() < N T pop_front(); }; Precondition: An obligation that the caller must fulfill for the program to be correct.
  34. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 34/168 Ringbuffer example template <typename T, int N> class ringbuffer { public: ringbuffer(); int size() const; void push_back(T); // requires: size() < N T pop_front(); }; Precondition: An obligation that the caller must fulfill for the program to be correct.
  35. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 35/168 Ringbuffer example template <typename T, int N> class ringbuffer { public: ringbuffer(); int size() const; void push_back(T); // requires: size() < N T pop_front(); }; Precondition: An obligation that the caller must fulfill for the program to be correct. Choose between: Define behaviour when empty, or make not-empty a precondition.
  36. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 36/168 Ringbuffer example template <typename T, int N> class ringbuffer { public: ringbuffer(); int size() const; void push_back(T); // requires: size() < N T pop_front(); // requires: size() > 0 }; Precondition: An obligation that the caller must fulfill for the program to be correct.
  37. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 37/168 Ringbuffer example template <typename T, int N> class ringbuffer { public: ringbuffer(); int size() const; void push_back(T); // requires: size() < N T pop_front(); // requires: size() > 0 }; Postcondition:
  38. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 38/168 Ringbuffer example template <typename T, int N> class ringbuffer { public: ringbuffer(); int size() const; void push_back(T); // requires: size() < N T pop_front(); // requires: size() > 0 }; Postcondition: A guarantee from the implementation regarding the effect of a legal call.
  39. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 39/168 Ringbuffer example template <typename T, int N> class ringbuffer { public: ringbuffer(); int size() const; void push_back(T); // requires: size() < N T pop_front(); // requires: size() > 0 }; Postcondition: A guarantee from the implementation regarding the effect of a legal call. A postcondition may refer to return value or the objects state, or both, sometimes dependent on parameter values
  40. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 40/168 Ringbuffer example template <typename T, int N> class ringbuffer { public: ringbuffer(); int size() const; void push_back(T); // requires: size() < N T pop_front(); // requires: size() > 0 }; Postcondition: A guarantee from the implementation regarding the effect of a legal call.
  41. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 41/168 Ringbuffer example template <typename T, int N> class ringbuffer { public: ringbuffer(); // ensures: size() /= 0 int size() const; void push_back(T); // requires: size() < N T pop_front(); // requires: size() > 0 }; Postcondition: A guarantee from the implementation regarding the effect of a legal call.
  42. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 42/168 Ringbuffer example template <typename T, int N> class ringbuffer { public: ringbuffer(); // ensures: size() /= 0 int size() const; void push_back(T); // requires: size() < N T pop_front(); // requires: size() > 0 }; Postcondition: A guarantee from the implementation regarding the effect of a legal call.
  43. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 43/168 Ringbuffer example template <typename T, int N> class ringbuffer { public: ringbuffer(); // ensures: size() /= 0 int size() const; void push_back(T); // requires: size() < N T pop_front(); // requires: size() > 0 }; Postcondition: A guarantee from the implementation regarding the effect of a legal call.
  44. Programming with Contracts in C++20 – ACCU 2019 © Björn

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

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

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

    Fahller @bjorn_fahller 47/168 Ringbuffer example template <typename T, int N> class ringbuffer { public: ringbuffer(); // ensures: size() /= 0 int size() const; const T& back() 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 }; Postcondition: A guarantee from the implementation regarding the effect of a legal call.
  48. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 48/168 Ringbuffer example template <typename T, int N> class ringbuffer { public: ringbuffer(); // ensures: size() /= 0 int size() const; const T& back() 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 }; Postcondition: A guarantee from the implementation regarding the effect of a legal call. What if an exception is thrown?
  49. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 49/168 Ringbuffer example template <typename T, int N> class ringbuffer { public: ringbuffer(); // ensures: size() /= 0 int size() const; const T& back() 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 }; Postcondition: A guarantee from the implementation regarding the effect of a legal call. Postconditions handles return. If an exception is thrown, there is no post condition.
  50. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 50/168 Ringbuffer example template <typename T, int N> class ringbuffer { public: ringbuffer(); // ensures: size() /= 0 int size() const; const T& back() 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 }; Postcondition: A guarantee from the implementation regarding the effect of a legal call.
  51. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 51/168 Ringbuffer example template <typename T, int N> class ringbuffer { public: ringbuffer(); // ensures: size() /= 0 int size() const; const T& back() 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 }; Postcondition: A guarantee from the implementation regarding the effect of a legal call.
  52. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 52/168 Ringbuffer example template <typename T, int N> class ringbuffer { public: ringbuffer(); // ensures: size() /= 0 int size() const; const T& back() const; // requires: size() > 0 const T& front() const; 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(); }; Postcondition: A guarantee from the implementation regarding the effect of a legal call.
  53. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 53/168 Ringbuffer example template <typename T, int N> class ringbuffer { public: 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(); }; Postcondition: A guarantee from the implementation regarding the effect of a legal call.
  54. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 54/168 Ringbuffer example template <typename T, int N> class ringbuffer { public: ringbuffer(); // ensures: size() /= 0 int size() const; const T& top() 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(); }; Postcondition: A guarantee from the implementation regarding the effect of a legal call. It does not make sense to try and express the returned value from the history of pushes and pops as a post condition.
  55. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 55/168 Ringbuffer example template <typename T, int N> class ringbuffer { public: ringbuffer(); // 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(); }; Class invariant:
  56. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 56/168 Ringbuffer example template <typename T, int N> class ringbuffer { public: ringbuffer(); // 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(); }; Class invariant: Something that is always* true for a valid instance * outside public API
  57. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 57/168 Ringbuffer example template <typename T, int N> class ringbuffer { public: ringbuffer(); // 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(); }; Class invariant: Something that is always* true for a valid instance * outside public API A class invariant always refers to state, and must be true even when exceptions are thrown.
  58. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 58/168 Ringbuffer example template <typename T, int N> class ringbuffer { public: // invariant: size() /= 0 /& size() /= N ringbuffer(); // 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(); }; Class invariant: Something that is always* true for a valid instance * outside public API
  59. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 59/168 Ringbuffer example template <typename T, int N> class ringbuffer { public: // invariant: size() /= 0 /& size() /= N ringbuffer(); // 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(); }; Class invariant: Something that is always* true for a valid instance * outside public API What about a moved-from object?
  60. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 60/168 Ringbuffer example template <typename T, int N> class ringbuffer { public: // invariant: size() /= 0 /& size() /= N ringbuffer(); // 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(); }; Contracts and templates
  61. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 61/168 Ringbuffer example template <typename T, int N> class ringbuffer { public: // invariant: size() /= 0 /& size() /= N ringbuffer(); // 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(); }; Contracts and templates What about specializations?
  62. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 62/168 Ringbuffer example template <typename T, int N> class ringbuffer { public: // invariant: size() /= 0 /& size() /= N ringbuffer(); // 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(); }; Contracts and inheritance:
  63. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 63/168 Ringbuffer example template <typename T, int N> class ringbuffer { public: // invariant: size() /= 0 /& size() /= N ringbuffer(); // 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(); }; Contracts and inheritance: A subcontractor may have more relaxed pre- conditions
  64. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 64/168 Ringbuffer example template <typename T, int N> class ringbuffer { public: // invariant: size() /= 0 /& size() /= N ringbuffer(); // 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(); }; Contracts and inheritance: A subcontractor may have more relaxed pre- conditions and stricter post- conditions
  65. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 65/168 Why bother?
  66. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 66/168 Why bother? 1)It can make interfaces much clearer
  67. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 67/168 Why bother? 1)It can make interfaces much clearer 2)It can make debugging much easier
  68. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 68/168 Why bother? 1)It can make interfaces much clearer 2)It can make debugging much easier 3)It removes defensive checks
  69. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 69/168 Who dunnit? guilty client implementation violation precondition postcondition invariant
  70. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 70/168 Who dunnit? guilty client implementation violation precondition postcondition invariant Elementary, Dr. Watson
  71. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 71/168 Who dunnit? guilty client implementation violation precondition postcondition invariant
  72. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 72/168 Who dunnit? guilty client implementation violation precondition postcondition invariant
  73. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 73/168 Who dunnit? guilty client implementation violation precondition postcondition invariant
  74. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 74/168 Who dunnit? guilty client implementation violation precondition postcondition invariant
  75. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 75/168 Who dunnit? guilty client implementation violation precondition postcondition invariant
  76. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 76/168 Who dunnit? guilty client implementation violation precondition postcondition invariant
  77. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 77/168 Who dunnit? guilty client implementation violation precondition postcondition invariant Or you have a bad contract!
  78. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 78/168 Contracts in C++20
  79. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 79/168 Contracts in C++20
  80. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 80/168 Contracts in C++20 Description of contract attribute declarations and semantics here (4 pages)
  81. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 81/168 Contracts in C++20 Description of contract violation handlers
  82. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 82/168 Contracts in C++20 Meaning for virtual functions (1 paragraph)
  83. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 83/168 Contracts in C++20 Contracts and templates (1 non-formative sentence)
  84. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 84/168 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-level opt : conditional-expression ] ] [ [ ensures contract-level opt identifier opt : conditional-expression ] ] [ [ assert contract-level opt : 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
  85. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 85/168 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-level opt : conditional-expression ] ] [ [ ensures contract-level opt identifier opt : conditional-expression ] ] [ [ assert contract-level opt : 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 Pre condition
  86. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 86/168 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-level opt : conditional-expression ] ] [ [ ensures contract-level opt identifier opt : conditional-expression ] ] [ [ assert contract-level opt : 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 Pre condition template <typename T> void func(std/:unique_ptr<T> p) [[ expects : p /= nullptr ]];
  87. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 87/168 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-level opt : conditional-expression ] ] [ [ ensures contract-level opt identifier opt : conditional-expression ] ] [ [ assert contract-level opt : 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 Optional level template <typename T> void func(std/:unique_ptr<T> p) [[ expects : p /= nullptr ]];
  88. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 88/168 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-level opt : conditional-expression ] ] [ [ ensures contract-level opt identifier opt : conditional-expression ] ] [ [ assert contract-level opt : 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 Optional level template <typename T> void func(std/:unique_ptr<T> p) [[ expects axiom : p /= nullptr ]];
  89. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 89/168 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-level opt : conditional-expression ] ] [ [ ensures contract-level opt identifier opt : conditional-expression ] ] [ [ assert contract-level opt : 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 Post condition
  90. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 90/168 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-level opt : conditional-expression ] ] [ [ ensures contract-level opt identifier opt : conditional-expression ] ] [ [ assert contract-level opt : 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 template <typename T> T prev(T v) [[ expects : v > 0 ]] [[ ensures audit r : r + 1 /= v ]]; Post condition
  91. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 91/168 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-level opt : conditional-expression ] ] [ [ ensures contract-level opt identifier opt : conditional-expression ] ] [ [ assert contract-level opt : 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 template <typename T> T prev(T v) [[ expects : v > 0 ]] [[ ensures audit r : r + 1 /= v ]]; Name for return value to use in conditional expression Post condition
  92. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 92/168 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-level opt : conditional-expression ] ] [ [ ensures contract-level opt identifier opt : conditional-expression ] ] [ [ assert contract-level opt : 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 Generic assertion
  93. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 93/168 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-level opt : conditional-expression ] ] [ [ ensures contract-level opt identifier opt : conditional-expression ] ] [ [ assert contract-level opt : 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 Generic assertion for (auto p : pointers) { [[ assert audit: p /= nullptr ]]; func(p); }
  94. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 94/168 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-level opt : conditional-expression ] ] [ [ ensures contract-level opt identifier opt : conditional-expression ] ] [ [ assert contract-level opt : 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 There are no class invariants!
  95. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 95/168 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(); };
  96. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 96/168 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(); };
  97. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 97/168 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(); }; No support for class invariants, so might as well leave as comment.
  98. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 98/168 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(); };
  99. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 99/168 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(); };
  100. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 100/168 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(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(); }; <source>:6:15: error: use of undeclared identifier 'size' [[ ensures: size() /= 0 ]];
  101. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 101/168 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(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(); }; <source>:6:15: error: use of undeclared identifier 'size' [[ ensures: size() /= 0 ]]; Contract attributes are declarations that can only refer to identifiers seen earlier.
  102. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 102/168 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(); }; Contract attributes are declarations that can only refer to identifiers seen earlier.
  103. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 103/168 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(); };
  104. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 104/168 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(); };
  105. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 105/168 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(); };
  106. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 106/168 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(); };
  107. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 107/168 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(); };
  108. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 108/168 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(); };
  109. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 109/168 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(); };
  110. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 110/168 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(); }; There is no way to refer to previous state so this cannot be expressed!
  111. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 111/168 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(); };
  112. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 112/168 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(); };
  113. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 113/168 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(); }; 6# If a function has multiple preconditions, their evaluation (if any) will be performed in the order they appear lexically. If a function has multiple postconditions, their evaluation (if any) will be performed in the order they appear lexically. [ Example: void f(int * p) [[expects: p != nullptr]] // #1 [[ensures: *p == 1]] // #3 [[expects: *p == 0]] // #2 { *p = 1; } — end example ] http://eel.is/c/+draft/dcl.attr.contract#cond-6
  114. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 114/168 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(); }; 6# If a function has multiple preconditions, their evaluation (if any) will be performed in the order they appear lexically. If a function has multiple postconditions, their evaluation (if any) will be performed in the order they appear lexically. [ Example: void f(int * p) [[expects: p != nullptr]] // #1 [[ensures: *p == 1]] // #3 [[expects: *p == 0]] // #2 { *p = 1; } — end example ] http://eel.is/c/+draft/dcl.attr.contract#cond-6
  115. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 115/168 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(); }; 7# If a postcondition odr-uses ([basic.def.odr]) a parameter in its predicate and the function body makes direct or indirect modifications of the value of that parameter, the behavior is undefined. [ Example: int f(int x) [[ensures r: r == x]] { return ++x; // undefined behavior } ... http://eel.is/c/+draft/dcl.attr.contract#cond-7
  116. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 116/168 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(); }; 7# If a postcondition odr-uses ([basic.def.odr]) a parameter in its predicate and the function body makes direct or indirect modifications of the value of that parameter, the behavior is undefined. [ Example: int f(int x) [[ensures r: r == x]] { return ++x; // undefined behavior } ... http://eel.is/c/+draft/dcl.attr.contract#cond-7 So the validity of the post condition declaration depends on how the function is implemented
  117. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 117/168 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(); }; Potentially dangerous
  118. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 118/168 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(); };
  119. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 119/168 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(); };
  120. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 120/168 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(); };
  121. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 121/168 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(); };
  122. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 122/168 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(); }; Cannot express condition with previous state so might as well leave as comment
  123. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 123/168 Virtual functions and contracts in C++20
  124. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 124/168 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
  125. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 125/168 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
  126. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 126/168 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
  127. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 127/168 Function pointers and contracts in C++20
  128. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 128/168 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
  129. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 129/168 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 In other words, it is the responsibility of a function implementation to enforce its contracts, not the caller.
  130. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 130/168 Let’s explore! https://github.com/arcosuc3m/clang-contracts Fork from clang-6 http://fragata.arcos.inf.uc3m.es/#
  131. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 131/168 Policing contracts in C++20
  132. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 132/168 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
  133. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 133/168 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
  134. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 134/168 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
  135. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 135/168 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
  136. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 136/168 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
  137. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 137/168 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
  138. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 138/168 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
  139. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 139/168 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 3.7 [defns.cond.supp] conditionally-supported program construct that an implementation is not required to support [ Note: Each implementation documents all conditionally-supported constructs that it does not support. — end note ] http://eel.is/c/+draft/intro.defs#defns.cond.supp
  140. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 140/168 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
  141. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 141/168 Let’s explore! https://github.com/arcosuc3m/clang-contracts Fork from clang-6 http://fragata.arcos.inf.uc3m.es/#
  142. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 142/168 Let’s explore! https://github.com/arcosuc3m/clang-contracts Fork from clang-6 http://fragata.arcos.inf.uc3m.es/# -build-level=(off|default|audit)
  143. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 143/168 When contracts are violated in C++20
  144. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 144/168 When contracts are violated in C++20 5# The violation handler of a program is a function of type “noexcept opt 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
  145. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 145/168 When contracts are violated in C++20 5# The violation handler of a program is a function of type “noexcept opt 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
  146. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 146/168 When contracts are violated in C++20 5# The violation handler of a program is a function of type “noexcept opt 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 16.8.2 Class contract_ violation [support.contract.cviol] namespace std { class contract_violation { public: uint_least32_t line_number() const noexcept; string_view file_name() const noexcept; string_view function_name() const noexcept; string_view comment() const noexcept; string_view assertion_level() const noexcept; }; } http://eel.is/c/+draft/support.contract.cviol
  147. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 147/168 When contracts are violated in C++20 5# The violation handler of a program is a function of type “noexcept opt 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
  148. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 148/168 When contracts are violated in C++20 5# The violation handler of a program is a function of type “noexcept opt 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
  149. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 149/168 When contracts are violated in C++20 5# The violation handler of a program is a function of type “noexcept opt 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
  150. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 150/168 Let’s explore! https://github.com/arcosuc3m/clang-contracts Fork from clang-6 -build-level=(off|default|audit) http://fragata.arcos.inf.uc3m.es/#
  151. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 151/168 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
  152. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 152/168 When contracts are violated in C++20
  153. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 153/168 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
  154. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 154/168 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
  155. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 155/168 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
  156. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 156/168 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
  157. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 157/168 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 [ Example: void f(int x) [[expects: x > 0]]; void g() { f(0); // std /: terminate() after handler if // continuation mode is off; // proceeds after handler if // continuation mode is on /* //. // } — end example ]
  158. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 158/168 Programming with Contracts in C++20 Björn Fahller
  159. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 159/168 Summary • Design by contract is a way to clarify the responsibility between a function implementation and its callers.
  160. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 160/168 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
  161. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 161/168 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
  162. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 162/168 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.
  163. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 163/168 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.
  164. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 164/168 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.
  165. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 165/168 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.
  166. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 166/168 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.
  167. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 167/168 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. Play with it! https://github.com/arcosuc3m/clang-contracts Fork from clang-6 http://fragata.arcos.inf.uc3m.es/#
  168. Programming with Contracts in C++20 – ACCU 2019 © Björn

    Fahller @bjorn_fahller 168/168 Björn Fahller Programming with Contracts in C++20 bjorn@fahller.se @bjorn_fahller @rollbear