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

[CppOnSea] Programming with Contracts in C++20

[CppOnSea] 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.

Björn Fahller

February 05, 2019
Tweet

More Decks by Björn Fahller

Other Decks in Programming

Transcript

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

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

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

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

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

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

    Fahller @bjorn_fahller 6/171 • Preconditions • Postconditions • Class invariants Contracts
  7. 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);
  8. Programming with Contracts in C++20 – C++onSea 2019 © Björn

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

    Fahller @bjorn_fahller 9/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 10/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 11/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 12/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 13/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 14/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 15/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 16/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 17/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 18/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 19/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 20/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 21/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 22/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 23/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 24/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 25/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 26/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 27/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 28/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 29/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 30/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 31/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 32/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 33/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 34/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 35/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 36/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 37/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 38/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 39/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 40/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 41/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 42/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 43/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 44/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 45/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 46/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 47/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 48/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 49/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 50/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 51/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 52/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 53/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 54/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 55/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 56/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 57/171 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 – 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(); // 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 – 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(); // 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 – 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(); // 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 61/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 62/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 63/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 64/171 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 65/171 Why bother?
  66. 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
  67. Programming with Contracts in C++20 – C++onSea 2019 © Björn

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    Fahller @bjorn_fahller 82/171 Contracts in C++20 Contracts and templates (1 non-formative sentence)
  83. 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-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
  84. 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-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
  85. 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-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 ]];
  86. 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-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 ]];
  87. 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-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 ]];
  88. 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-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
  89. 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. 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
  90. 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-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
  91. 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-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
  92. 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 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 axiom: p /= nullptr ]]; func(p); }
  93. Programming with Contracts in C++20 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 93/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-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!
  94. 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(); };
  95. 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: // 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 – 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(); }; No support for class invariants, so might as well leave as comment.
  97. 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(); };
  98. 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; // 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 – C++onSea 2019 © Björn

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

    Fahller @bjorn_fahller 100/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(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.
  101. 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(); }; Contract attributes are declarations that can only refer to identifiers seen earlier.
  102. 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; // 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(); };
  103. 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(); };
  104. 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; // 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 – 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 front(); };
  106. 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); // requires: size() < N // ensures: size() /= old size()+1 // back() /= t T pop_front(); // requires: size() > 0 // ensures: size() /= old size()-1 // return /= old back(); };
  107. 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 back(); };
  108. 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: // 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 – 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() /= 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!
  110. 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(); };
  111. 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, 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 112/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(); }; 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
  113. 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, 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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 114/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(); }; 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
  115. 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() [[ 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
  116. 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(); }; Potentially dangerous
  117. 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(); // requires: size() > 0 // ensures: size() /= old size()-1 // return /= old front(); };
  118. 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(); };
  119. 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() /= old size()-1 // return /= old front(); };
  120. 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 ]]; 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(); };
  121. Programming with Contracts in C++20 – C++onSea 2019 © Björn

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

    Fahller @bjorn_fahller 122/171 Virtual functions and contracts in C++20
  123. 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
  124. 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
  125. Programming with Contracts in C++20 – C++onSea 2019 © Björn

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

    Fahller @bjorn_fahller 126/171 Function pointers and contracts in C++20
  127. 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]] { 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
  128. Programming with Contracts in C++20 – C++onSea 2019 © Björn

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

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

    Fahller @bjorn_fahller 130/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 P1320R1 Allowing contract predicates on non-first declarations Ville Voutilainen struct X { void f(); }; void X/:f() [[expects: foo]] { //. }
  131. Programming with Contracts in C++20 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 131/171 Policing contracts in C++20
  132. 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
  133. 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
  134. 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
  135. 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
  136. 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 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 – 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 P1421r0 Assigning semantics to different Contract Checking Statements Andrzej Krzemieński Allowing different levels for different types of contracts, e.g. audit on preconditions, and off on the others.
  138. 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
  139. Programming with Contracts in C++20 – C++onSea 2019 © Björn

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

    Fahller @bjorn_fahller 141/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
  142. 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/#
  143. Programming with Contracts in C++20 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 143/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)
  144. Programming with Contracts in C++20 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 144/171 When contracts are violated in C++20
  145. 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 “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 – 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 “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
  147. 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 “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
  148. 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 “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 – 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 “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 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 150/171 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
  151. 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 -build-level=(off|default|audit) http://fragata.arcos.inf.uc3m.es/#
  152. Programming with Contracts in C++20 – C++onSea 2019 © Björn

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

    Fahller @bjorn_fahller 153/171 When contracts are violated in C++20
  154. 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
  155. 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
  156. 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
  157. 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 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
  158. 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. 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 ]
  159. Programming with Contracts in C++20 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 159/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 P1429r0 - Contracts that work Joshua Bern, John Lakos Distinguishing between violations that can be safely continued from, and violations that are fatal.
  160. Programming with Contracts in C++20 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 160/171 Programming with Contracts in C++20 Björn Fahller
  161. 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.
  162. 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
  163. 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
  164. 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.
  165. 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.
  166. 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.
  167. 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 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.
  168. 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. P1426r0 Pull the Plug on Contracts? Nathan Meyers. Argues that the whole idea got wrong and should be scrapped and replaced with something else.
  169. Programming with Contracts in C++20 – C++onSea 2019 © Björn

    Fahller @bjorn_fahller 169/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.
  170. Programming with Contracts in C++20 – C++onSea 2019 © Björn

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

    Fahller @bjorn_fahller 171/171 Björn Fahller Programming with Contracts in C++20 [email protected] @bjorn_fahller @rollbear