static modeling (& lifetime) using types to test, document and reduce system complexity
TRANSCRIPT
Safety nets• Design/code reviews, pair programming• Compiler • Static modeling• Unit tests/module tests• Pipeline tests• Developer testing• Continuos integration• Static analysis tools (PCLint etc)• Dynamic analysis tools (Boundschecker, valgrind, etc)• QA testing• Design by contract• Assertions
Bold = expressed in code
Fail fast• Minimize turn around time – minimize waste• Bug found => ”Possible to catch earlier?”• Review => ”Possible to catch earlier?”
Failing fast in C++Build timeCode generationMacro expansionTemplate instantiationTranslation unit compilationLinking Installation/configuration
Run timeLoad timeStatic initializationBootstrapping/Initialization codeLevel load ... Specific/rare situations
Static modeling• Model invariants and tests with (static) types• Either compile time or instantiation time
int x=-10;bounded<int, -1, 99999> i(x);
quantity<speed> v = 1*meter/second;quantity<time> t = 2.0*minute;quantity<length> l = v/t;
Value of static modeling
1. Type up ASAP - fail fast2. Documentation3. Reduces complexity / state space
Code based tests
Static modeling, assertions, design by contract, automated test hooks, unit tests etc.
- Add ”weight” when prototyping+ ”Easy” to add to existing/legacy code
How to reduce the state space• Init/set/modify -> constructor/factory• Split objects into smaller pieces• Lock down dynamics ASAP
Distuinguish invalid ids by typeenum error {err1, err2};
class result { bool has_id(); const
/// @pre valid() foo_id get_id() const;
/// @pre !valid() error get_error() const;private: int data;};
result get_id(...);
// Using boostboost::variant<error, foo_id> get_id();
Optional
optional<X> find_closest_x();void do_stuff(const X& x);
• Isolate inited/not inited state• Clear semantics, all-or-nothing
bool find_closest_x(X& x);
Right/left hand system
Either compile time, runtime or combinedBetter granularity than math asserts on/off
RAII• new/delete • aquire/unaquire• connect/disconnect• lock/unlock• subscribe/unsubscribe• register/unregister• open/close
Need to match call pairs AND know if an objectis initialized or not
RAII example
void foo(int x, int y);
signal<void(int x, int y)> sig;signal_connection con(sig, foo);
Static modeling and lifetime• More work in constructor/destructor• Object lifetime becomes very important
Lifetime primitives• scoped_ptr (not copyable)• shared_ptr• weak_ptr• move_ptr (not copyable)• reference (not assignable)
Interfaceless objects/// @param foo is guaranteed to outlive/// return valuemove_ptr<void> create_stuff(const function<void()>& onBar,
shared_ptr<GuiFactories> gui,
const SomeFacade& foo, move_ptr<const ResourceX> x);
Summary• Static modeling pros: Fails fast, documentation, minimizes
total logic • Static modeling increasingly important in longer and larger
projects• Static modeling increases need of clear lifetime semantics
Static modeling vs. DbC
Catch errors that must be checked at runtime bytyping up or DbC/assertions?
• Is the invariant local?• Duplicate preconditions => time to type up!• S.M. only applicable to single variables
Opposite of static modeling
class message_channel{ void send(const string& key, const string& value); void listen(const string& key, listener& l) const;};
Dynamic modeling good for prototyping/iteratingOptimal: Lock down invariants in code by typing up
incrementally. No major language supports this well.