Design by Contract (or contract-driven development) helps in ensuring software correctness without compromising performance* and system complexity. The checks are defined as preconditions, postconditions and invariants. For more information on Design By Contract in general, see section Further Resources.
*Effect on performance depends on enforcement semantics. Also, strong typing may be treated as a form of design by contract.
Free functions:
using namespace rdbc = roboss::dbc;
constexpr bool f_pre(int input1) {
return CHECK(input1 > 2);
}
constexpr bool f_post(double ret) {
return CHECK(ret < 0.5);
}
double f(int input1, rdbc::PrePost<&f_pre, &f_post> contract = {}) {
contract.pre_check(input1);
// ...my function body...
return contract.post_check(0.2);
}Member functions:
using namespace rdbc = roboss::dbc;
class MyClass : rdbc::Contractual {
public:
static constexpr bool class_precond(int member_var) {
return CHECK(member_var > 1)
}
MyClass(int member_var = 2, rdbc::Pre<&MyClass::class_precond> contract = {})
: rdbc::Contractual(contract, member_var),
a_member_variable_{member_var}
{}
constexpr bool f_pre(int input1) const {
return CHECK(input1 > 2)
&& CHECK(a_member_variable_ == 2);
}
constexpr bool f_post(double ret) const {
return CHECK(ret < 0.5)
&& CHECK(a_member_variable_ == 3);
}
double f(int input1, rdbc::PrePost<&MyClass::f_pre, &MyClass::f_post> contract = {}) {
contract.pre_check(this, input1);
// ...my function body...
a_member_variable_ = 3;
return contract.post_check(this, 0.2);
}
private:
int a_member_variable_;
};- Contract is (optionally) part of the function declaration
- Program termination if the pre- or postconditions of the function are not checked
- Preconditions may be switched off on the call site
- Constructor preconditions
- Conditions can also be explicitly checked on call site
- Contract semantics configurable via compiler flags (TODO)