SlideShare a Scribd company logo
1 of 120
Download to read offline
Mateusz Pusz
September 27, 2018
EFFECTIVE REPLACEMENT OF
DYNAMIC POLYMORPHISM
WITH std::variant
WHY?
• Time required to perform some action or to produce some result
• Measured in units of time like hours, minutes, seconds, nanoseconds or clock periods
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
WHY?
LATENCY
3
• Time required to perform some action or to produce some result
• Measured in units of time like hours, minutes, seconds, nanoseconds or clock periods
• In capital markets, the use of algorithmic trading to react to market events faster than the competition
to increase profitability of trades
• Many use cases where predictability of latency in message delivery is just as important, if not more
important than achieving a low average latency
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
WHY?
LATENCY
LOW LATENCY
3
• In Low Latency system we care a lot about
WCET (Worst Case Execution Time)
• In order to limit WCET we should limit the
usage of specific C++ language features
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
HOW NOT TO DEVELOP SOFTWARE THAT HAVE PREDICTABLE
PERFORMANCE?
4
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
THINGS TO AVOID ON THE FAST PATH
5
• C++ tools that trade performance for usability (e.g. std::shared_ptr, std::function)
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
THINGS TO AVOID ON THE FAST PATH
5
• C++ tools that trade performance for usability (e.g. std::shared_ptr, std::function)
• Throwing exceptions on likely code path
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
THINGS TO AVOID ON THE FAST PATH
5
• C++ tools that trade performance for usability (e.g. std::shared_ptr, std::function)
• Throwing exceptions on likely code path
• Dynamic polymorphism
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
THINGS TO AVOID ON THE FAST PATH
5
• C++ tools that trade performance for usability (e.g. std::shared_ptr, std::function)
• Throwing exceptions on likely code path
• Dynamic polymorphism
• Multiple inheritance
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
THINGS TO AVOID ON THE FAST PATH
5
• C++ tools that trade performance for usability (e.g. std::shared_ptr, std::function)
• Throwing exceptions on likely code path
• Dynamic polymorphism
• Multiple inheritance
• RTTI
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
THINGS TO AVOID ON THE FAST PATH
5
• C++ tools that trade performance for usability (e.g. std::shared_ptr, std::function)
• Throwing exceptions on likely code path
• Dynamic polymorphism
• Multiple inheritance
• RTTI
• Dynamic memory allocations
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
THINGS TO AVOID ON THE FAST PATH
5
• Dynamic polymorphism
• Dynamic memory allocations
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
THINGS TO AVOID ON THE FAST PATH
• C++ tools that trade performance for usability (e.g. std::shared_ptr, std::function)
• Throwing exceptions on likely code path
• Multiple inheritance
• RTTI
6
HOW?
class base : noncopyable {
public:
virtual ~base() = default;
virtual void foo() = 0;
};
class x : public base {
public:
void foo() override;
};
class y : public base {
public:
void foo() override;
};
std::unique_ptr<base> b = std::make_unique<x>();
b->foo();
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
HOW?
DYNAMIC POLYMORPHISM
8
class base : noncopyable {
public:
virtual ~base() = default;
virtual void foo() = 0;
};
class x : public base {
public:
void foo() override;
};
class y : public base {
public:
void foo() override;
};
std::unique_ptr<base> b = std::make_unique<x>();
b->foo();
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
HOW?
DYNAMIC POLYMORPHISM
8
class base : noncopyable {
public:
virtual ~base() = default;
virtual void foo() = 0;
};
class x : public base {
public:
void foo() override;
};
class y : public base {
public:
void foo() override;
};
struct x { void foo(); };
struct y { void foo(); };
std::variant<x, y> b;
std::visit([](auto&& v){ v.foo(); }, b);
• Shorter
• Faster
• Value semantics
• Works on unrelated classes
• More flexible thanks to duck typing
std::unique_ptr<base> b = std::make_unique<x>();
b->foo();
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
HOW?
DYNAMIC POLYMORPHISM VARIANT
8
BONUS SLIDES
Abstract machine that can be in exactly one of a finite number of
states at any given time.
-- Wikipedia
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
FINITE STATE MACHINE
11
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
FINITE STATE MACHINE
12
• State changes to another in a response to
some external inputs called events
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
FINITE STATE MACHINE
12
• State changes to another in a response to
some external inputs called events
• The change from one state to another is
called a transition
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
FINITE STATE MACHINE
12
• State changes to another in a response to
some external inputs called events
• The change from one state to another is
called a transition
• A FSM is defined by
– a list of states
– its initial state
– the conditions for each transition
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
FINITE STATE MACHINE
12
SINGLE DYNAMIC DISPATCH
CASE #1
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
CLASS DIAGRAM
14
template<typename Event>
class state : noncopyable {
public:
virtual ~state() = default;
virtual std::unique_ptr<state> on_event(Event) = 0;
};
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
SINGLE DYNAMIC DISPATCH
15
template<typename Event>
class state : noncopyable {
public:
virtual ~state() = default;
virtual std::unique_ptr<state> on_event(Event) = 0;
};
template<typename Event>
class fsm {
std::unique_ptr<state<Event>> state_;
public:
explicit fsm(std::unique_ptr<state<Event>> state) : state_(std::move(state)) {}
void dispatch(Event e)
{
auto new_state = state_->on_event(e);
if (new_state)
state_ = std::move(new_state);
}
};
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
SINGLE DYNAMIC DISPATCH
15
template<typename Event>
class state : noncopyable {
public:
virtual ~state() = default;
virtual std::unique_ptr<state> on_event(Event) = 0;
};
template<typename Event>
class fsm {
std::unique_ptr<state<Event>> state_;
public:
explicit fsm(std::unique_ptr<state<Event>> state) : state_(std::move(state)) {}
void dispatch(Event e)
{
auto new_state = state_->on_event(e);
if (new_state)
state_ = std::move(new_state);
}
};
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
SINGLE DYNAMIC DISPATCH
16
class connection_fsm : public fsm<event> {
public:
connection_fsm():
fsm<event>(std::make_unique<state_idle>()) {}
};
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
CONNECTION FSM
17
class connection_fsm : public fsm<event> {
public:
connection_fsm():
fsm<event>(std::make_unique<state_idle>()) {}
};
using s = state<event>;
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
CONNECTION FSM
17
class connection_fsm : public fsm<event> {
public:
connection_fsm():
fsm<event>(std::make_unique<state_idle>()) {}
};
using s = state<event>;
class state_idle final : public s {
public:
std::unique_ptr<s> on_event(event e) override;
};
class state_connecting final : public s {
static constexpr int n_max = 3;
int n = 0;
public:
std::unique_ptr<s> on_event(event e) override;
};
class state_connected final : public s {
public:
std::unique_ptr<s> on_event(event e) override;
};
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
CONNECTION FSM
17
std::unique_ptr<s> state_idle::on_event(event e)
{
}
std::unique_ptr<s> state_connecting::on_event(event e)
{
}
std::unique_ptr<s> state_connected::on_event(event e)
{
}
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
TRANSITIONS
18
std::unique_ptr<s> state_idle::on_event(event e)
{
if(e == event::connect)
return std::make_unique<state_connecting>();
return nullptr;
}
std::unique_ptr<s> state_connecting::on_event(event e)
{
}
std::unique_ptr<s> state_connected::on_event(event e)
{
}
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
TRANSITIONS
18
std::unique_ptr<s> state_idle::on_event(event e)
{
if(e == event::connect)
return std::make_unique<state_connecting>();
return nullptr;
}
std::unique_ptr<s> state_connecting::on_event(event e)
{
switch(e) {
case event::connected:
return std::make_unique<state_connected>();
case event::timeout:
return ++n < n_max ?
nullptr : std::make_unique<state_idle>();
default:
return nullptr;
}
}
std::unique_ptr<s> state_connected::on_event(event e)
{
}
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
TRANSITIONS
18
std::unique_ptr<s> state_idle::on_event(event e)
{
if(e == event::connect)
return std::make_unique<state_connecting>();
return nullptr;
}
std::unique_ptr<s> state_connecting::on_event(event e)
{
switch(e) {
case event::connected:
return std::make_unique<state_connected>();
case event::timeout:
return ++n < n_max ?
nullptr : std::make_unique<state_idle>();
default:
return nullptr;
}
}
std::unique_ptr<s> state_connected::on_event(event e)
{
if(e == event::disconnect)
return std::make_unique<state_idle>();
return nullptr;
}
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
TRANSITIONS
18
std::unique_ptr<s> state_idle::on_event(event e)
{
if(e == event::connect)
return std::make_unique<state_connecting>();
return nullptr;
}
std::unique_ptr<s> state_connecting::on_event(event e)
{
switch(e) {
case event::connected:
return std::make_unique<state_connected>();
case event::timeout:
return ++n < n_max ?
nullptr : std::make_unique<state_idle>();
default:
return nullptr;
}
}
std::unique_ptr<s> state_connected::on_event(event e)
{
if(e == event::disconnect)
return std::make_unique<state_idle>();
return nullptr;
}
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
THE SLOW PART
19
• Fold expressions come handy ;-)
template<typename Fsm, typename... Events>
void dispatch(Fsm& fsm, Events... events)
{
(fsm.dispatch(events), ...);
}
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
TESTING TRANSITIONS
20
• Fold expressions come handy ;-)
template<typename Fsm, typename... Events>
void dispatch(Fsm& fsm, Events... events)
{
(fsm.dispatch(events), ...);
}
• Simple message flow
connection_fsm fsm;
dispatch(fsm, event::connect, event::timeout, event::connected, event::disconnect);
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
TESTING TRANSITIONS
20
• Open to new alternatives
– new derived types may be added by clients at any point of time (long a er base class
implementation is finished)
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
SINGLE DYNAMIC DISPATCH
21
• Open to new alternatives
– new derived types may be added by clients at any point of time (long a er base class
implementation is finished)
• Closed to new operations
– clients cannot add new operations to dynamic dispatch
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
SINGLE DYNAMIC DISPATCH
21
• Open to new alternatives
– new derived types may be added by clients at any point of time (long a er base class
implementation is finished)
• Closed to new operations
– clients cannot add new operations to dynamic dispatch
• Multi-level
– many levels of inheritance possible
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
SINGLE DYNAMIC DISPATCH
21
• Open to new alternatives
– new derived types may be added by clients at any point of time (long a er base class
implementation is finished)
• Closed to new operations
– clients cannot add new operations to dynamic dispatch
• Multi-level
– many levels of inheritance possible
• Object Oriented
– whole framework is based on objects
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
SINGLE DYNAMIC DISPATCH
21
DOUBLE DYNAMIC DISPATCH
CASE #2
class event : noncopyable {
public:
virtual ~event() = default;
};
class event_connect final : public event {
std::string_view address_;
public:
explicit event_connect(std::string_view address): address_(address) {}
std::string_view address() const { return address_; }
};
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
WHAT IF WE WANT OUR EVENTS TO PASS DATA?
23
class event : noncopyable {
public:
virtual ~event() = default;
};
class event_connect final : public event {
std::string_view address_;
public:
explicit event_connect(std::string_view address): address_(address) {}
std::string_view address() const { return address_; }
};
std::unique_ptr<state> state_idle::on_event(const event& e)
{
if(auto ptr = dynamic_cast<const event_connect*>(&e)) { /* ... */ }
else { /* ... */ }
}
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
WHAT IF WE WANT OUR EVENTS TO PASS DATA?
23
class event : noncopyable {
public:
virtual ~event() = default;
};
class event_connect final : public event {
std::string_view address_;
public:
explicit event_connect(std::string_view address): address_(address) {}
std::string_view address() const { return address_; }
};
std::unique_ptr<state> state_idle::on_event(const event& e)
{
if(auto ptr = dynamic_cast<const event_connect*>(&e)) { /* ... */ }
else { /* ... */ }
}
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
WHAT IF WE WANT OUR EVENTS TO PASS DATA?
A really bad idea :-(
23
Special form of multiple dispatch, and a mechanism that
dispatches a function call to di erent concrete functions
depending on the runtime types of two objects involved in the call
-- Wikipedia
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
DOUBLE DISPATCH (AKA VISITOR PATTERN)
24
template<typename State>
struct event : private noncopyable {
virtual ~event() = default;
virtual std::unique_ptr<State> dispatch(State& s) const = 0;
};
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
DOUBLE DISPATCH (AKA VISITOR PATTERN)
25
template<typename State>
struct event : private noncopyable {
virtual ~event() = default;
virtual std::unique_ptr<State> dispatch(State& s) const = 0;
};
template<typename State, typename Event>
class fsm {
std::unique_ptr<State> state_;
public:
explicit fsm(std::unique_ptr<State> state) : state_(std::move(state)) {}
void dispatch(const Event& e)
{
auto new_state = e.dispatch(*state_);
if (new_state)
state_ = std::move(new_state);
}
};
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
DOUBLE DISPATCH (AKA VISITOR PATTERN)
25
template<typename State>
struct event : private noncopyable {
virtual ~event() = default;
virtual std::unique_ptr<State> dispatch(State& s) const = 0;
};
struct event_connect final : public event<state> {
std::unique_ptr<state> dispatch(state& s) const override { return s.on_event(*this); }
// ...
};
struct event_connected final : public event<state> {
std::unique_ptr<state> dispatch(state& s) const override { return s.on_event(*this); }
};
struct event_disconnect final : public event<state> {
std::unique_ptr<state> dispatch(state& s) const override { return s.on_event(*this); }
};
struct event_timeout final : public event<state> {
std::unique_ptr<state> dispatch(state& s) const override { return s.on_event(*this); }
};
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
DOUBLE DISPATCH (AKA VISITOR PATTERN)
26
template<typename State>
struct event : private noncopyable {
virtual ~event() = default;
virtual std::unique_ptr<State> dispatch(State& s) const = 0;
};
class state : noncopyable {
public:
virtual ~state() = default;
virtual std::unique_ptr<state> on_event(const event_connect&) { return nullptr; }
virtual std::unique_ptr<state> on_event(const event_connected&) { return nullptr; }
virtual std::unique_ptr<state> on_event(const event_disconnect&) { return nullptr; }
virtual std::unique_ptr<state> on_event(const event_timeout&) { return nullptr; }
};
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
DOUBLE DISPATCH (AKA VISITOR PATTERN)
27
template<typename State>
struct event : private noncopyable {
virtual ~event() = default;
virtual std::unique_ptr<State> dispatch(State& s) const = 0;
};
class state : noncopyable {
public:
virtual ~state() = default;
virtual std::unique_ptr<state> on_event(const event_connect&) { return nullptr; }
virtual std::unique_ptr<state> on_event(const event_connected&) { return nullptr; }
virtual std::unique_ptr<state> on_event(const event_disconnect&) { return nullptr; }
virtual std::unique_ptr<state> on_event(const event_timeout&) { return nullptr; }
};
class state_idle final : public state {
public:
using state::on_event;
std::unique_ptr<state> on_event(const event_connect& e) override
{
return std::make_unique<state_connecting>(std::string(e.address()));
}
};
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
DOUBLE DISPATCH (AKA VISITOR PATTERN)
27
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
CLASS DIAGRAM
28
template<typename State>
struct event : private noncopyable {
virtual ~event() = default;
virtual std::unique_ptr<State> dispatch(State& s) const = 0;
};
struct event_connect final : public event<state> {
std::unique_ptr<state> dispatch(state& s) const override { return s.on_event(*this); }
// ...
};
struct event_connected final : public event<state> {
std::unique_ptr<state> dispatch(state& s) const override { return s.on_event(*this); }
};
struct event_disconnect final : public event<state> {
std::unique_ptr<state> dispatch(state& s) const override { return s.on_event(*this); }
};
struct event_timeout final : public event<state> {
std::unique_ptr<state> dispatch(state& s) const override { return s.on_event(*this); }
};
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
CURIOUSLY RECURRING TEMPLATE PATTERN (CRTP)
29
template<typename State>
struct event : private noncopyable {
virtual ~event() = default;
virtual std::unique_ptr<State> dispatch(State& s) const = 0;
};
template<typename Child>
struct event_crtp : event<state> {
std::unique_ptr<state> dispatch(state& s) const override { return s.on_event(*static_cast<const Child*>(this)); }
};
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
CURIOUSLY RECURRING TEMPLATE PATTERN (CRTP)
30
template<typename State>
struct event : private noncopyable {
virtual ~event() = default;
virtual std::unique_ptr<State> dispatch(State& s) const = 0;
};
template<typename Child>
struct event_crtp : event<state> {
std::unique_ptr<state> dispatch(state& s) const override { return s.on_event(*static_cast<const Child*>(this)); }
};
struct event_connect final : public event_crtp<event_connect> {
// ...
};
struct event_connected final : public event_crtp<event_connected> {};
struct event_disconnect final : public event_crtp<event_disconnect> {};
struct event_timeout final : public event_crtp<event_timeout> {};
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
CURIOUSLY RECURRING TEMPLATE PATTERN (CRTP)
30
template<typename State>
struct event : private noncopyable {
virtual ~event() = default;
virtual std::unique_ptr<State> dispatch(State& s) const = 0;
};
template<typename Child>
struct event_crtp : event<state> {
std::unique_ptr<state> dispatch(state& s) const override { return s.on_event(*static_cast<const Child*>(this)); }
};
struct event_connect final : public event_crtp<event_connect> {
explicit event_connect(std::string_view address): address_(address) {}
std::string_view address() const { return address_; }
private:
std::string_view address_;
};
struct event_connected final : public event_crtp<event_connected> {};
struct event_disconnect final : public event_crtp<event_disconnect> {};
struct event_timeout final : public event_crtp<event_timeout> {};
• Hey look ma, now all fits on one slide ;-)
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
CURIOUSLY RECURRING TEMPLATE PATTERN (CRTP)
31
std::unique_ptr<state>
state_idle::on_event(const event_connect& e)
{
}
std::unique_ptr<state>
state_connecting::on_event(const event_connected&)
{
}
std::unique_ptr<state>
state_connecting::on_event(const event_timeout&)
{
}
std::unique_ptr<state>
state_connected::on_event(const event_disconnect&)
{
}
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
TRANSITIONS
32
std::unique_ptr<state>
state_idle::on_event(const event_connect& e)
{
return std::make_unique<state_connecting>(
std::string{e.address()});
}
std::unique_ptr<state>
state_connecting::on_event(const event_connected&)
{
}
std::unique_ptr<state>
state_connecting::on_event(const event_timeout&)
{
}
std::unique_ptr<state>
state_connected::on_event(const event_disconnect&)
{
}
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
TRANSITIONS
32
std::unique_ptr<state>
state_idle::on_event(const event_connect& e)
{
return std::make_unique<state_connecting>(
std::string{e.address()});
}
std::unique_ptr<state>
state_connecting::on_event(const event_connected&)
{
return std::make_unique<state_connected>();
}
std::unique_ptr<state>
state_connecting::on_event(const event_timeout&)
{
}
std::unique_ptr<state>
state_connected::on_event(const event_disconnect&)
{
}
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
TRANSITIONS
32
std::unique_ptr<state>
state_idle::on_event(const event_connect& e)
{
return std::make_unique<state_connecting>(
std::string{e.address()});
}
std::unique_ptr<state>
state_connecting::on_event(const event_connected&)
{
return std::make_unique<state_connected>();
}
std::unique_ptr<state>
state_connecting::on_event(const event_timeout&)
{
return ++n < n_max ?
nullptr : std::make_unique<state_idle>();
}
std::unique_ptr<state>
state_connected::on_event(const event_disconnect&)
{
}
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
TRANSITIONS
32
std::unique_ptr<state>
state_idle::on_event(const event_connect& e)
{
return std::make_unique<state_connecting>(
std::string{e.address()});
}
std::unique_ptr<state>
state_connecting::on_event(const event_connected&)
{
return std::make_unique<state_connected>();
}
std::unique_ptr<state>
state_connecting::on_event(const event_timeout&)
{
return ++n < n_max ?
nullptr : std::make_unique<state_idle>();
}
std::unique_ptr<state>
state_connected::on_event(const event_disconnect&)
{
return std::make_unique<state_idle>();
}
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
TRANSITIONS
32
std::unique_ptr<state>
state_idle::on_event(const event_connect& e)
{
return std::make_unique<state_connecting>(
std::string{e.address()});
}
std::unique_ptr<state>
state_connecting::on_event(const event_connected&)
{
return std::make_unique<state_connected>();
}
std::unique_ptr<state>
state_connecting::on_event(const event_timeout&)
{
return ++n < n_max ?
nullptr : std::make_unique<state_idle>();
}
std::unique_ptr<state>
state_connected::on_event(const event_disconnect&)
{
return std::make_unique<state_idle>();
}
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
THE SLOW PART
33
template<typename Fsm, typename... Events>
void dispatch(Fsm& fsm, const Events&... events)
{
(fsm.dispatch(*events), ...);
}
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
TESTING TRANSITIONS
34
template<typename Fsm, typename... Events>
void dispatch(Fsm& fsm, const Events&... events)
{
(fsm.dispatch(*events), ...);
}
dispatch(fsm,
std::make_unique<event_connect>("train-it.eu"),
std::make_unique<event_timeout>(),
std::make_unique<event_connected>(),
std::make_unique<event_disconnect>());
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
TESTING TRANSITIONS
34
template<typename Fsm, typename... Events>
void dispatch(Fsm& fsm, const Events&... events)
{
(fsm.dispatch(*events), ...);
}
dispatch(fsm,
std::make_unique<event_connect>("train-it.eu"),
std::make_unique<event_timeout>(),
std::make_unique<event_connected>(),
std::make_unique<event_disconnect>());
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
THE SLOW PART
35
• Open to new alternatives
• Closed to new alternatives
– one of class hierarchies fixed at design time and cannot be extended by clients
• Closed to new operations
– clients cannot add new operations to dynamic dispatch
• Multi-level
– many levels of inheritance possible
• Object Oriented
– whole framework is based on objects
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
DOUBLE DYNAMIC DISPATCH (AKA VISITOR PATTERN)
36
std:variant IN 3 MINUTES
template<class... Types>
class variant;
• Represents a type-safe union
• At any given point in time either
– holds a value of one of its alternative types
– is in special valueless_by_exception state (reached if an exception is thrown during contained
value initialization or assignment)
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
std::variant<Types...>
38
// not a valid C++
template<typename Type1, typename Type2, typename Type3...>
class variant {
union options {
Type1 t1;
Type2 t2;
Type3 t3;
...
};
int index_;
public:
variant();
template<class T> variant(T&& t);
template<class T, class... Args> variant(std::in_place_type_t<T>, Args&&... args);
std::size_t index() const;
//...
};
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
std::variant<Types...> INTERFACE (SIMPLIFICATION)
39
• Not allowed to allocate dynamic memory
• Not permitted to hold references, arrays, or void
• Empty variants are ill-formed (std::variant<std::monostate> can be used instead)
• Permitted to hold the same type more than once, and to hold di erently cv-qualified versions of the
same type
• Default-initialized variant holds a value of its first alternative unless that alternative is not default-
constructible
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
std::variant<Types...>
40
void print(const std::variant<int, double, X>& v)
{
switch (v.index()) {
case 0: std::cout << "int: " << std::get<0>(v) << 'n'; break;
case 1: std::cout << "double: " << std::get<1>(v) << 'n'; break;
case 2: std::cout << "X: " << std::get<2>(v).x << ", " << std::get<2>(v).y << 'n'; break;
}
}
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
std::variant<Types...>
41
void print(const std::variant<int, double, X>& v)
{
switch (v.index()) {
case 0: std::cout << "int: " << std::get<0>(v) << 'n'; break;
case 1: std::cout << "double: " << std::get<1>(v) << 'n'; break;
case 2: std::cout << "X: " << std::get<2>(v).x << ", " << std::get<2>(v).y << 'n'; break;
}
}
struct visitor {
void operator()(int v) const { std::cout << "int: " << v << 'n'; }
void operator()(double v) const { std::cout << "double: " << v << 'n'; }
void operator()(const X& v) const { std::cout << "X: " << v.x << ", " << v.y << 'n'; }
};
void print(const std::variant<int, double, X>& v) { std::visit(visitor{}, v); }
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
std::variant<Types...>
41
VARIANT + EXTERNAL TRANSITIONS
CASE #3
struct event_connect { std::string_view address; };
struct event_connected {};
struct event_disconnect {};
struct event_timeout {};
using event = std::variant<event_connect, event_connected, event_disconnect, event_timeout>;
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
EVENTS AND STATES
EVENTS
43
struct event_connect { std::string_view address; };
struct event_connected {};
struct event_disconnect {};
struct event_timeout {};
using event = std::variant<event_connect, event_connected, event_disconnect, event_timeout>;
struct state_idle {};
struct state_connecting {
static constexpr int n_max = 3;
int n = 0;
std::string address;
};
struct state_connected {};
using state = std::variant<state_idle, state_connecting, state_connected>;
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
EVENTS AND STATES
EVENTS
STATES
43
struct transitions {
optional<state> operator()(state_idle&,
const event_connect& e)
{ }
optional<state> operator()(state_connecting&,
const event_connected&)
{ }
optional<state> operator()(state_connecting& s,
const event_timeout&)
{
}
optional<state> operator()(state_connected&,
const event_disconnect&)
{ }
};
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
TRANSITIONS
44
struct transitions {
optional<state> operator()(state_idle&,
const event_connect& e)
{ return state_connecting{std::string(e.address)}; }
optional<state> operator()(state_connecting&,
const event_connected&)
{ }
optional<state> operator()(state_connecting& s,
const event_timeout&)
{
}
optional<state> operator()(state_connected&,
const event_disconnect&)
{ }
};
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
TRANSITIONS
44
struct transitions {
optional<state> operator()(state_idle&,
const event_connect& e)
{ return state_connecting{std::string(e.address)}; }
optional<state> operator()(state_connecting&,
const event_connected&)
{ return state_connected{}; }
optional<state> operator()(state_connecting& s,
const event_timeout&)
{
}
optional<state> operator()(state_connected&,
const event_disconnect&)
{ }
};
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
TRANSITIONS
44
struct transitions {
optional<state> operator()(state_idle&,
const event_connect& e)
{ return state_connecting{std::string(e.address)}; }
optional<state> operator()(state_connecting&,
const event_connected&)
{ return state_connected{}; }
optional<state> operator()(state_connecting& s,
const event_timeout&)
{
return ++s.n < state_connecting::n_max ?
std::nullopt : optional<state>(state_idle{});
}
optional<state> operator()(state_connected&,
const event_disconnect&)
{ }
};
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
TRANSITIONS
44
struct transitions {
optional<state> operator()(state_idle&,
const event_connect& e)
{ return state_connecting{std::string(e.address)}; }
optional<state> operator()(state_connecting&,
const event_connected&)
{ return state_connected{}; }
optional<state> operator()(state_connecting& s,
const event_timeout&)
{
return ++s.n < state_connecting::n_max ?
std::nullopt : optional<state>(state_idle{});
}
optional<state> operator()(state_connected&,
const event_disconnect&)
{ return state_idle{}; }
};
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
TRANSITIONS
44
struct transitions {
optional<state> operator()(state_idle&,
const event_connect& e)
{ return state_connecting{std::string(e.address)}; }
optional<state> operator()(state_connecting&,
const event_connected&)
{ return state_connected{}; }
optional<state> operator()(state_connecting& s,
const event_timeout&)
{
return ++s.n < state_connecting::n_max ?
std::nullopt : optional<state>(state_idle{});
}
optional<state> operator()(state_connected&,
const event_disconnect&)
{ return state_idle{}; }
template<typename State, typename Event>
optional<state> operator()(State&,
const Event&) const
{ return std::nullopt; }
};
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
TRANSITIONS
44
template<typename StateVariant, typename EventVariant, typename Transitions>
class fsm {
StateVariant state_;
public:
void dispatch(const EventVariant& event)
{
std::optional<StateVariant> new_state = std::visit(Transitions{}, state_, event);
if(new_state)
state_ = *std::move(new_state);
}
};
using connection_fsm = fsm<state, event, transitions>;
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
FSM ENGINE
45
template<typename StateVariant, typename EventVariant, typename Transitions>
class fsm {
StateVariant state_;
public:
void dispatch(const EventVariant& event)
{
std::optional<StateVariant> new_state = std::visit(Transitions{}, state_, event);
if(new_state)
state_ = *std::move(new_state);
}
};
using connection_fsm = fsm<state, event, transitions>;
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
FSM ENGINE
46
template<typename StateVariant, typename EventVariant, typename Transitions>
class fsm {
StateVariant state_;
public:
void dispatch(const EventVariant& event)
{
std::optional<StateVariant> new_state = std::visit(Transitions{}, state_, event);
if(new_state)
state_ = *std::move(new_state);
}
};
using connection_fsm = fsm<state, event, transitions>;
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
FSM ENGINE
47
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
CLASS DIAGRAM
48
template<typename Fsm, typename... Events>
void dispatch(Fsm& fsm, Events&&... events)
{
(fsm.dispatch(std::forward<Events>(events)), ...);
}
dispatch(fsm,
event_connect{"train-it.eu"},
event_timeout{},
event_connected{},
event_disconnect{});
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
TESTING TRANSITIONS
49
VARIANT + TRANSITIONS IN FSM
CASE #4
template<typename Derived, typename StateVariant, typename EventVariant>
class fsm {
StateVariant state_;
public:
void dispatch(const EventVariant& event)
{
auto new_state = std::visit(
state_, event);
if(new_state)
state_ = *std::move(new_state);
}
};
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
FSM ENGINE
51
template<typename Derived, typename StateVariant, typename EventVariant>
class fsm {
StateVariant state_;
public:
void dispatch(const EventVariant& event)
{
Derived& child = static_cast<Derived&>(*this);
auto new_state = std::visit(
[&](auto& s, const auto& e) -> std::optional<StateVariant>
{ return child.on_event(s, e); },
state_, event);
if(new_state)
state_ = *std::move(new_state);
}
};
• CRTP again ;-)
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
FSM ENGINE
51
template<typename Derived, typename StateVariant>
class fsm {
StateVariant state_;
public:
template<typename Event>
void dispatch(Event&& event)
{
Derived& child = static_cast<Derived&>(*this);
auto new_state = std::visit(
[&](auto& s) -> std::optional<StateVariant>
{ return child.on_event(s, std::forward<Event>(event)); },
state_);
if(new_state)
state_ = *std::move(new_state);
}
};
• Variant of events not needed anymore
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
FSM ENGINE
52
class connection_fsm
: public fsm<connection_fsm, state> {
public:
auto on_event(state_idle&,
const event_connect& e)
{ }
auto on_event(state_connecting&,
const event_connected&)
{ }
auto on_event(state_connecting& s,
const event_timeout&)
{
}
auto on_event(state_connected&,
const event_disconnect&)
{ }
template<typename State, typename Event>
auto on_event(State&, const Event&)
{ }
};
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
TRANSITIONS DEFINED BY THE FSM ITSELF
53
class connection_fsm
: public fsm<connection_fsm, state> {
public:
auto on_event(state_idle&,
const event_connect& e)
{ return state_connecting{std::string(e.address)}; }
auto on_event(state_connecting&,
const event_connected&)
{ return state_connected{}; }
auto on_event(state_connecting& s,
const event_timeout&)
{
return ++s.n < state_connecting::n_max ?
std::nullopt : std::optional<state>(state_idle{});
}
auto on_event(state_connected&,
const event_disconnect&)
{ return state_idle{}; }
template<typename State, typename Event>
auto on_event(State&, const Event&)
{ return std::nullopt; }
};
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
TRANSITIONS DEFINED BY THE FSM ITSELF
53
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
CLASS DIAGRAM
54
VARIANT + TRANSITIONS IN STATES
CASE #5
template<typename StateVariant, typename OnInvalidTransition>
class fsm {
StateVariant state_;
public:
template<typename Event>
void dispatch(Event&& event)
{
auto new_state = std::visit(overloaded{
}, state_);
if(new_state)
state_ = *std::move(new_state);
}
};
• Beware, lambdas are coming :-)
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
FSM ENGINE
56
template<typename StateVariant, typename OnInvalidTransition>
class fsm {
StateVariant state_;
public:
template<typename Event>
void dispatch(Event&& event)
{
auto new_state = std::visit(overloaded{
[&](auto& s, decltype(s.on_event(event))* = nullptr) -> std::optional<StateVariant>
{ return s.on_event(std::forward<Event>(event)); },
}, state_);
if(new_state)
state_ = *std::move(new_state);
}
};
• Thanks to SFINAE matches defined transitions only
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
FSM ENGINE
57
template<typename StateVariant, typename OnInvalidTransition>
class fsm {
StateVariant state_;
public:
template<typename Event>
void dispatch(Event&& event)
{
auto new_state = std::visit(overloaded{
[&](auto& s, decltype(s.on_event(event))* = nullptr) -> std::optional<StateVariant>
{ return s.on_event(std::forward<Event>(event)); },
[&](auto&... s) -> std::optional<StateVariant>
{ return OnInvalidTransition()(s..., std::forward<Event>(event)); }
}, state_);
if(new_state)
state_ = *std::move(new_state);
}
};
• Worse overload thanks to a template parameter pack usage
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
FSM ENGINE
58
auto state_idle::on_event(const event_connect& e)
{
return state_connecting{std::string(e.address)};
}
auto state_connecting::on_event(const event_connected&)
{
return state_connected{};
}
auto state_connecting::on_event(const event_timeout&)
{
return ++n_ < n_max ? std::nullopt
: std::optional<state>(state_idle{});
}
auto state_connected::on_event(const event_disconnect&)
{
return state_idle{};
}
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
TRANSITIONS DEFINED BY STATES
59
auto state_idle::on_event(const event_connect& e)
{
return state_connecting{std::string(e.address)};
}
auto state_connecting::on_event(const event_connected&)
{
return state_connected{};
}
auto state_connecting::on_event(const event_timeout&)
{
return ++n_ < n_max ? std::nullopt
: std::optional<state>(state_idle{});
}
auto state_connected::on_event(const event_disconnect&)
{
return state_idle{};
}
struct ignore_unknown_event {
template<typename State, typename Event>
auto operator()(const State&, const Event&)
{ return std::nullopt; }
};
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
TRANSITIONS DEFINED BY STATES
59
WHAT ABOUT PERFORMANCE?
CLOSED(Start)
LISTEN/-
CLOSE/-
LISTEN
SYN
RECEIVED
SYN
SENT
CONNECT/ (Step 1 of the 3-way-handshake)SYN
SYN/SYN+ACK(Step 2 of the 3-way-handshake)
unusual event
client/receiver path
server/sender path
RST/-
SYN/SYN+ACK (simultaneous open)
SYN+ACK/ACK
(Step 3 of the 3-way-handshake)
Data exchange occurs
ESTABLISHED
FIN/ACK
ACK/-
CLOSE/-
SEND/SYN
CLOSE/FIN
CLOSE/FIN
CLOSING
TIME WAIT
CLOSED
FIN WAIT 1
FIN WAIT 2
CLOSE WAIT
LAST ACK
CLOSE/FIN
FIN/ACK
FIN+ACK/ACK
ACK/-
FIN/ACK
Timeout
(Go back to start)
Active CLOSE Passive CLOSE
ACK/-
ACK/-
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
TCP STATE DIAGRAM
61
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
TCP FSM PERFORMANCE
62
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
TCP FSM PERFORMANCE
62
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
TCP FSM PERFORMANCE
62
SUMMARY
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
std::variant<Types...> VS INHERITANCE
INHERITANCE VARIANT
64
• Open/Closed to new alternatives • Closed to new alternatives
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
std::variant<Types...> VS INHERITANCE
INHERITANCE VARIANT
64
• Open/Closed to new alternatives
• Closed to new operations
• Closed to new alternatives
• Open to new operations
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
std::variant<Types...> VS INHERITANCE
INHERITANCE VARIANT
64
• Open/Closed to new alternatives
• Closed to new operations
• Multi-level
• Closed to new alternatives
• Open to new operations
• Single level
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
std::variant<Types...> VS INHERITANCE
INHERITANCE VARIANT
64
• Open/Closed to new alternatives
• Closed to new operations
• Multi-level
• OO
• Closed to new alternatives
• Open to new operations
• Single level
• Functional
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
std::variant<Types...> VS INHERITANCE
INHERITANCE VARIANT
64
• Open/Closed to new alternatives
• Closed to new operations
• Multi-level
• OO
• Pointer semantics
• Closed to new alternatives
• Open to new operations
• Single level
• Functional
• Value semantics
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
std::variant<Types...> VS INHERITANCE
INHERITANCE VARIANT
64
• Open/Closed to new alternatives
• Closed to new operations
• Multi-level
• OO
• Pointer semantics
• Design forced by the implementation details
• Closed to new alternatives
• Open to new operations
• Single level
• Functional
• Value semantics
• Many design choices possible
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
std::variant<Types...> VS INHERITANCE
INHERITANCE VARIANT
64
• Open/Closed to new alternatives
• Closed to new operations
• Multi-level
• OO
• Pointer semantics
• Design forced by the implementation details
• Forces dynamic memory allocations
• Closed to new alternatives
• Open to new operations
• Single level
• Functional
• Value semantics
• Many design choices possible
• No dynamic memory allocations
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
std::variant<Types...> VS INHERITANCE
INHERITANCE VARIANT
64
• Open/Closed to new alternatives
• Closed to new operations
• Multi-level
• OO
• Pointer semantics
• Design forced by the implementation details
• Forces dynamic memory allocations
• Strict interfaces
• Closed to new alternatives
• Open to new operations
• Single level
• Functional
• Value semantics
• Many design choices possible
• No dynamic memory allocations
• Duck typing
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
std::variant<Types...> VS INHERITANCE
INHERITANCE VARIANT
64
• Open/Closed to new alternatives
• Closed to new operations
• Multi-level
• OO
• Pointer semantics
• Design forced by the implementation details
• Forces dynamic memory allocations
• Strict interfaces
• Complex
• Closed to new alternatives
• Open to new operations
• Single level
• Functional
• Value semantics
• Many design choices possible
• No dynamic memory allocations
• Duck typing
• Simple
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
std::variant<Types...> VS INHERITANCE
INHERITANCE VARIANT
64
• Open/Closed to new alternatives
• Closed to new operations
• Multi-level
• OO
• Pointer semantics
• Design forced by the implementation details
• Forces dynamic memory allocations
• Strict interfaces
• Complex
• Slower
• Closed to new alternatives
• Open to new operations
• Single level
• Functional
• Value semantics
• Many design choices possible
• No dynamic memory allocations
• Duck typing
• Simple
• Faster
CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant
std::variant<Types...> VS INHERITANCE
INHERITANCE VARIANT
64
Effective replacement of dynamic polymorphism with std::variant
Effective replacement of dynamic polymorphism with std::variant

More Related Content

Similar to Effective replacement of dynamic polymorphism with std::variant

Combining Phase Identification and Statistic Modeling for Automated Parallel ...
Combining Phase Identification and Statistic Modeling for Automated Parallel ...Combining Phase Identification and Statistic Modeling for Automated Parallel ...
Combining Phase Identification and Statistic Modeling for Automated Parallel ...
Mingliang Liu
 
Flink Forward San Francisco 2019: Streaming your Lyft Ride Prices - Thomas We...
Flink Forward San Francisco 2019: Streaming your Lyft Ride Prices - Thomas We...Flink Forward San Francisco 2019: Streaming your Lyft Ride Prices - Thomas We...
Flink Forward San Francisco 2019: Streaming your Lyft Ride Prices - Thomas We...
Flink Forward
 
Flink Forward San Francisco 2019: Streaming your Lyft Ride Prices - Thomas We...
Flink Forward San Francisco 2019: Streaming your Lyft Ride Prices - Thomas We...Flink Forward San Francisco 2019: Streaming your Lyft Ride Prices - Thomas We...
Flink Forward San Francisco 2019: Streaming your Lyft Ride Prices - Thomas We...
Flink Forward
 
Flowex: Flow-Based Programming with Elixir GenStage - Anton Mishchuk
Flowex: Flow-Based Programming with Elixir GenStage - Anton MishchukFlowex: Flow-Based Programming with Elixir GenStage - Anton Mishchuk
Flowex: Flow-Based Programming with Elixir GenStage - Anton Mishchuk
Elixir Club
 

Similar to Effective replacement of dynamic polymorphism with std::variant (20)

The magic behind your Lyft ride prices: A case study on machine learning and ...
The magic behind your Lyft ride prices: A case study on machine learning and ...The magic behind your Lyft ride prices: A case study on machine learning and ...
The magic behind your Lyft ride prices: A case study on machine learning and ...
 
Combining Phase Identification and Statistic Modeling for Automated Parallel ...
Combining Phase Identification and Statistic Modeling for Automated Parallel ...Combining Phase Identification and Statistic Modeling for Automated Parallel ...
Combining Phase Identification and Statistic Modeling for Automated Parallel ...
 
Miroforidis Slides PP97-2003
Miroforidis Slides PP97-2003Miroforidis Slides PP97-2003
Miroforidis Slides PP97-2003
 
Applying Linear Optimization Using GLPK
Applying Linear Optimization Using GLPKApplying Linear Optimization Using GLPK
Applying Linear Optimization Using GLPK
 
Streaming your Lyft Ride Prices - Flink Forward SF 2019
Streaming your Lyft Ride Prices - Flink Forward SF 2019Streaming your Lyft Ride Prices - Flink Forward SF 2019
Streaming your Lyft Ride Prices - Flink Forward SF 2019
 
Flink Forward San Francisco 2019: Streaming your Lyft Ride Prices - Thomas We...
Flink Forward San Francisco 2019: Streaming your Lyft Ride Prices - Thomas We...Flink Forward San Francisco 2019: Streaming your Lyft Ride Prices - Thomas We...
Flink Forward San Francisco 2019: Streaming your Lyft Ride Prices - Thomas We...
 
Flink Forward San Francisco 2019: Streaming your Lyft Ride Prices - Thomas We...
Flink Forward San Francisco 2019: Streaming your Lyft Ride Prices - Thomas We...Flink Forward San Francisco 2019: Streaming your Lyft Ride Prices - Thomas We...
Flink Forward San Francisco 2019: Streaming your Lyft Ride Prices - Thomas We...
 
Virtual function
Virtual functionVirtual function
Virtual function
 
P4_tutorial.pdf
P4_tutorial.pdfP4_tutorial.pdf
P4_tutorial.pdf
 
HPC on Cloud for SMEs. The case of bolt tightening.
HPC on Cloud for SMEs. The case of bolt tightening.HPC on Cloud for SMEs. The case of bolt tightening.
HPC on Cloud for SMEs. The case of bolt tightening.
 
Flowex - Railway Flow-Based Programming with Elixir GenStage.
Flowex - Railway Flow-Based Programming with Elixir GenStage.Flowex - Railway Flow-Based Programming with Elixir GenStage.
Flowex - Railway Flow-Based Programming with Elixir GenStage.
 
Flowex: Flow-Based Programming with Elixir GenStage - Anton Mishchuk
Flowex: Flow-Based Programming with Elixir GenStage - Anton MishchukFlowex: Flow-Based Programming with Elixir GenStage - Anton Mishchuk
Flowex: Flow-Based Programming with Elixir GenStage - Anton Mishchuk
 
Tech Talk - Konrad Gawda : P4 programming language
Tech Talk - Konrad Gawda : P4 programming languageTech Talk - Konrad Gawda : P4 programming language
Tech Talk - Konrad Gawda : P4 programming language
 
Data Science at Scale on MPP databases - Use Cases & Open Source Tools
Data Science at Scale on MPP databases - Use Cases & Open Source ToolsData Science at Scale on MPP databases - Use Cases & Open Source Tools
Data Science at Scale on MPP databases - Use Cases & Open Source Tools
 
An Empirical Study On Practicality Of Specification Mining Algorithms On A Re...
An Empirical Study On Practicality Of Specification Mining Algorithms On A Re...An Empirical Study On Practicality Of Specification Mining Algorithms On A Re...
An Empirical Study On Practicality Of Specification Mining Algorithms On A Re...
 
Make gRPC great again
Make gRPC great againMake gRPC great again
Make gRPC great again
 
A challenge for thread parallelism on OpenFOAM
A challenge for thread parallelism on OpenFOAMA challenge for thread parallelism on OpenFOAM
A challenge for thread parallelism on OpenFOAM
 
From GameMaker to Game Baker - Porting Hotline Miami
From GameMaker to Game Baker - Porting Hotline MiamiFrom GameMaker to Game Baker - Porting Hotline Miami
From GameMaker to Game Baker - Porting Hotline Miami
 
PODS 2013 - Montali - Verification of Relational Data-Centric Dynamic Systems...
PODS 2013 - Montali - Verification of Relational Data-Centric Dynamic Systems...PODS 2013 - Montali - Verification of Relational Data-Centric Dynamic Systems...
PODS 2013 - Montali - Verification of Relational Data-Centric Dynamic Systems...
 
Open mp
Open mpOpen mp
Open mp
 

More from Mateusz Pusz

More from Mateusz Pusz (14)

Free Lunch is Over: Why is C++ so Important in the Modern World?
Free Lunch is Over: Why is C++ so Important in the Modern World?Free Lunch is Over: Why is C++ so Important in the Modern World?
Free Lunch is Over: Why is C++ so Important in the Modern World?
 
A Physical Units Library for the Next C++
A Physical Units Library for the Next C++A Physical Units Library for the Next C++
A Physical Units Library for the Next C++
 
Striving for ultimate Low Latency
Striving for ultimate Low LatencyStriving for ultimate Low Latency
Striving for ultimate Low Latency
 
Rethinking the Way We do Templates in C++
Rethinking the Way We do Templates in C++Rethinking the Way We do Templates in C++
Rethinking the Way We do Templates in C++
 
C++11 Was Only the Beginning
C++11 Was Only the BeginningC++11 Was Only the Beginning
C++11 Was Only the Beginning
 
Implementing a Physical Units Library for C++
Implementing a Physical Units Library for C++Implementing a Physical Units Library for C++
Implementing a Physical Units Library for C++
 
Implementing Physical Units Library for C++
Implementing Physical Units Library for C++Implementing Physical Units Library for C++
Implementing Physical Units Library for C++
 
C++ Concepts and Ranges - How to use them?
C++ Concepts and Ranges - How to use them?C++ Concepts and Ranges - How to use them?
C++ Concepts and Ranges - How to use them?
 
Git, CMake, Conan - How to ship and reuse our C++ projects?
Git, CMake, Conan - How to ship and reuse our C++ projects?Git, CMake, Conan - How to ship and reuse our C++ projects?
Git, CMake, Conan - How to ship and reuse our C++ projects?
 
Beyond C++17
Beyond C++17Beyond C++17
Beyond C++17
 
Pointless Pointers - How to make our interfaces efficient?
Pointless Pointers - How to make our interfaces efficient?Pointless Pointers - How to make our interfaces efficient?
Pointless Pointers - How to make our interfaces efficient?
 
Striving for ultimate Low Latency
Striving for ultimate Low LatencyStriving for ultimate Low Latency
Striving for ultimate Low Latency
 
Small Lie in Big O
Small Lie in Big OSmall Lie in Big O
Small Lie in Big O
 
std::shared_ptr<T> - (not so) Smart hammer for every pointy nail
std::shared_ptr<T> - (not so) Smart hammer for every pointy nailstd::shared_ptr<T> - (not so) Smart hammer for every pointy nail
std::shared_ptr<T> - (not so) Smart hammer for every pointy nail
 

Recently uploaded

Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
WSO2
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
panagenda
 

Recently uploaded (20)

CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistan
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
AI in Action: Real World Use Cases by Anitaraj
AI in Action: Real World Use Cases by AnitarajAI in Action: Real World Use Cases by Anitaraj
AI in Action: Real World Use Cases by Anitaraj
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptx
 
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
 
Vector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptxVector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptx
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
 
Platformless Horizons for Digital Adaptability
Platformless Horizons for Digital AdaptabilityPlatformless Horizons for Digital Adaptability
Platformless Horizons for Digital Adaptability
 
Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024
 

Effective replacement of dynamic polymorphism with std::variant

  • 1. Mateusz Pusz September 27, 2018 EFFECTIVE REPLACEMENT OF DYNAMIC POLYMORPHISM WITH std::variant
  • 3. • Time required to perform some action or to produce some result • Measured in units of time like hours, minutes, seconds, nanoseconds or clock periods CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant WHY? LATENCY 3
  • 4. • Time required to perform some action or to produce some result • Measured in units of time like hours, minutes, seconds, nanoseconds or clock periods • In capital markets, the use of algorithmic trading to react to market events faster than the competition to increase profitability of trades • Many use cases where predictability of latency in message delivery is just as important, if not more important than achieving a low average latency CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant WHY? LATENCY LOW LATENCY 3
  • 5. • In Low Latency system we care a lot about WCET (Worst Case Execution Time) • In order to limit WCET we should limit the usage of specific C++ language features CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant HOW NOT TO DEVELOP SOFTWARE THAT HAVE PREDICTABLE PERFORMANCE? 4
  • 6. CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant THINGS TO AVOID ON THE FAST PATH 5
  • 7. • C++ tools that trade performance for usability (e.g. std::shared_ptr, std::function) CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant THINGS TO AVOID ON THE FAST PATH 5
  • 8. • C++ tools that trade performance for usability (e.g. std::shared_ptr, std::function) • Throwing exceptions on likely code path CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant THINGS TO AVOID ON THE FAST PATH 5
  • 9. • C++ tools that trade performance for usability (e.g. std::shared_ptr, std::function) • Throwing exceptions on likely code path • Dynamic polymorphism CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant THINGS TO AVOID ON THE FAST PATH 5
  • 10. • C++ tools that trade performance for usability (e.g. std::shared_ptr, std::function) • Throwing exceptions on likely code path • Dynamic polymorphism • Multiple inheritance CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant THINGS TO AVOID ON THE FAST PATH 5
  • 11. • C++ tools that trade performance for usability (e.g. std::shared_ptr, std::function) • Throwing exceptions on likely code path • Dynamic polymorphism • Multiple inheritance • RTTI CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant THINGS TO AVOID ON THE FAST PATH 5
  • 12. • C++ tools that trade performance for usability (e.g. std::shared_ptr, std::function) • Throwing exceptions on likely code path • Dynamic polymorphism • Multiple inheritance • RTTI • Dynamic memory allocations CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant THINGS TO AVOID ON THE FAST PATH 5
  • 13. • Dynamic polymorphism • Dynamic memory allocations CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant THINGS TO AVOID ON THE FAST PATH • C++ tools that trade performance for usability (e.g. std::shared_ptr, std::function) • Throwing exceptions on likely code path • Multiple inheritance • RTTI 6
  • 14. HOW?
  • 15. class base : noncopyable { public: virtual ~base() = default; virtual void foo() = 0; }; class x : public base { public: void foo() override; }; class y : public base { public: void foo() override; }; std::unique_ptr<base> b = std::make_unique<x>(); b->foo(); CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant HOW? DYNAMIC POLYMORPHISM 8
  • 16. class base : noncopyable { public: virtual ~base() = default; virtual void foo() = 0; }; class x : public base { public: void foo() override; }; class y : public base { public: void foo() override; }; std::unique_ptr<base> b = std::make_unique<x>(); b->foo(); CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant HOW? DYNAMIC POLYMORPHISM 8
  • 17. class base : noncopyable { public: virtual ~base() = default; virtual void foo() = 0; }; class x : public base { public: void foo() override; }; class y : public base { public: void foo() override; }; struct x { void foo(); }; struct y { void foo(); }; std::variant<x, y> b; std::visit([](auto&& v){ v.foo(); }, b); • Shorter • Faster • Value semantics • Works on unrelated classes • More flexible thanks to duck typing std::unique_ptr<base> b = std::make_unique<x>(); b->foo(); CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant HOW? DYNAMIC POLYMORPHISM VARIANT 8
  • 18.
  • 20. Abstract machine that can be in exactly one of a finite number of states at any given time. -- Wikipedia CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant FINITE STATE MACHINE 11
  • 21. CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant FINITE STATE MACHINE 12
  • 22. • State changes to another in a response to some external inputs called events CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant FINITE STATE MACHINE 12
  • 23. • State changes to another in a response to some external inputs called events • The change from one state to another is called a transition CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant FINITE STATE MACHINE 12
  • 24. • State changes to another in a response to some external inputs called events • The change from one state to another is called a transition • A FSM is defined by – a list of states – its initial state – the conditions for each transition CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant FINITE STATE MACHINE 12
  • 26. CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant CLASS DIAGRAM 14
  • 27. template<typename Event> class state : noncopyable { public: virtual ~state() = default; virtual std::unique_ptr<state> on_event(Event) = 0; }; CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant SINGLE DYNAMIC DISPATCH 15
  • 28. template<typename Event> class state : noncopyable { public: virtual ~state() = default; virtual std::unique_ptr<state> on_event(Event) = 0; }; template<typename Event> class fsm { std::unique_ptr<state<Event>> state_; public: explicit fsm(std::unique_ptr<state<Event>> state) : state_(std::move(state)) {} void dispatch(Event e) { auto new_state = state_->on_event(e); if (new_state) state_ = std::move(new_state); } }; CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant SINGLE DYNAMIC DISPATCH 15
  • 29. template<typename Event> class state : noncopyable { public: virtual ~state() = default; virtual std::unique_ptr<state> on_event(Event) = 0; }; template<typename Event> class fsm { std::unique_ptr<state<Event>> state_; public: explicit fsm(std::unique_ptr<state<Event>> state) : state_(std::move(state)) {} void dispatch(Event e) { auto new_state = state_->on_event(e); if (new_state) state_ = std::move(new_state); } }; CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant SINGLE DYNAMIC DISPATCH 16
  • 30. class connection_fsm : public fsm<event> { public: connection_fsm(): fsm<event>(std::make_unique<state_idle>()) {} }; CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant CONNECTION FSM 17
  • 31. class connection_fsm : public fsm<event> { public: connection_fsm(): fsm<event>(std::make_unique<state_idle>()) {} }; using s = state<event>; CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant CONNECTION FSM 17
  • 32. class connection_fsm : public fsm<event> { public: connection_fsm(): fsm<event>(std::make_unique<state_idle>()) {} }; using s = state<event>; class state_idle final : public s { public: std::unique_ptr<s> on_event(event e) override; }; class state_connecting final : public s { static constexpr int n_max = 3; int n = 0; public: std::unique_ptr<s> on_event(event e) override; }; class state_connected final : public s { public: std::unique_ptr<s> on_event(event e) override; }; CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant CONNECTION FSM 17
  • 33. std::unique_ptr<s> state_idle::on_event(event e) { } std::unique_ptr<s> state_connecting::on_event(event e) { } std::unique_ptr<s> state_connected::on_event(event e) { } CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant TRANSITIONS 18
  • 34. std::unique_ptr<s> state_idle::on_event(event e) { if(e == event::connect) return std::make_unique<state_connecting>(); return nullptr; } std::unique_ptr<s> state_connecting::on_event(event e) { } std::unique_ptr<s> state_connected::on_event(event e) { } CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant TRANSITIONS 18
  • 35. std::unique_ptr<s> state_idle::on_event(event e) { if(e == event::connect) return std::make_unique<state_connecting>(); return nullptr; } std::unique_ptr<s> state_connecting::on_event(event e) { switch(e) { case event::connected: return std::make_unique<state_connected>(); case event::timeout: return ++n < n_max ? nullptr : std::make_unique<state_idle>(); default: return nullptr; } } std::unique_ptr<s> state_connected::on_event(event e) { } CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant TRANSITIONS 18
  • 36. std::unique_ptr<s> state_idle::on_event(event e) { if(e == event::connect) return std::make_unique<state_connecting>(); return nullptr; } std::unique_ptr<s> state_connecting::on_event(event e) { switch(e) { case event::connected: return std::make_unique<state_connected>(); case event::timeout: return ++n < n_max ? nullptr : std::make_unique<state_idle>(); default: return nullptr; } } std::unique_ptr<s> state_connected::on_event(event e) { if(e == event::disconnect) return std::make_unique<state_idle>(); return nullptr; } CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant TRANSITIONS 18
  • 37. std::unique_ptr<s> state_idle::on_event(event e) { if(e == event::connect) return std::make_unique<state_connecting>(); return nullptr; } std::unique_ptr<s> state_connecting::on_event(event e) { switch(e) { case event::connected: return std::make_unique<state_connected>(); case event::timeout: return ++n < n_max ? nullptr : std::make_unique<state_idle>(); default: return nullptr; } } std::unique_ptr<s> state_connected::on_event(event e) { if(e == event::disconnect) return std::make_unique<state_idle>(); return nullptr; } CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant THE SLOW PART 19
  • 38. • Fold expressions come handy ;-) template<typename Fsm, typename... Events> void dispatch(Fsm& fsm, Events... events) { (fsm.dispatch(events), ...); } CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant TESTING TRANSITIONS 20
  • 39. • Fold expressions come handy ;-) template<typename Fsm, typename... Events> void dispatch(Fsm& fsm, Events... events) { (fsm.dispatch(events), ...); } • Simple message flow connection_fsm fsm; dispatch(fsm, event::connect, event::timeout, event::connected, event::disconnect); CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant TESTING TRANSITIONS 20
  • 40. • Open to new alternatives – new derived types may be added by clients at any point of time (long a er base class implementation is finished) CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant SINGLE DYNAMIC DISPATCH 21
  • 41. • Open to new alternatives – new derived types may be added by clients at any point of time (long a er base class implementation is finished) • Closed to new operations – clients cannot add new operations to dynamic dispatch CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant SINGLE DYNAMIC DISPATCH 21
  • 42. • Open to new alternatives – new derived types may be added by clients at any point of time (long a er base class implementation is finished) • Closed to new operations – clients cannot add new operations to dynamic dispatch • Multi-level – many levels of inheritance possible CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant SINGLE DYNAMIC DISPATCH 21
  • 43. • Open to new alternatives – new derived types may be added by clients at any point of time (long a er base class implementation is finished) • Closed to new operations – clients cannot add new operations to dynamic dispatch • Multi-level – many levels of inheritance possible • Object Oriented – whole framework is based on objects CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant SINGLE DYNAMIC DISPATCH 21
  • 45. class event : noncopyable { public: virtual ~event() = default; }; class event_connect final : public event { std::string_view address_; public: explicit event_connect(std::string_view address): address_(address) {} std::string_view address() const { return address_; } }; CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant WHAT IF WE WANT OUR EVENTS TO PASS DATA? 23
  • 46. class event : noncopyable { public: virtual ~event() = default; }; class event_connect final : public event { std::string_view address_; public: explicit event_connect(std::string_view address): address_(address) {} std::string_view address() const { return address_; } }; std::unique_ptr<state> state_idle::on_event(const event& e) { if(auto ptr = dynamic_cast<const event_connect*>(&e)) { /* ... */ } else { /* ... */ } } CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant WHAT IF WE WANT OUR EVENTS TO PASS DATA? 23
  • 47. class event : noncopyable { public: virtual ~event() = default; }; class event_connect final : public event { std::string_view address_; public: explicit event_connect(std::string_view address): address_(address) {} std::string_view address() const { return address_; } }; std::unique_ptr<state> state_idle::on_event(const event& e) { if(auto ptr = dynamic_cast<const event_connect*>(&e)) { /* ... */ } else { /* ... */ } } CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant WHAT IF WE WANT OUR EVENTS TO PASS DATA? A really bad idea :-( 23
  • 48. Special form of multiple dispatch, and a mechanism that dispatches a function call to di erent concrete functions depending on the runtime types of two objects involved in the call -- Wikipedia CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant DOUBLE DISPATCH (AKA VISITOR PATTERN) 24
  • 49. template<typename State> struct event : private noncopyable { virtual ~event() = default; virtual std::unique_ptr<State> dispatch(State& s) const = 0; }; CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant DOUBLE DISPATCH (AKA VISITOR PATTERN) 25
  • 50. template<typename State> struct event : private noncopyable { virtual ~event() = default; virtual std::unique_ptr<State> dispatch(State& s) const = 0; }; template<typename State, typename Event> class fsm { std::unique_ptr<State> state_; public: explicit fsm(std::unique_ptr<State> state) : state_(std::move(state)) {} void dispatch(const Event& e) { auto new_state = e.dispatch(*state_); if (new_state) state_ = std::move(new_state); } }; CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant DOUBLE DISPATCH (AKA VISITOR PATTERN) 25
  • 51. template<typename State> struct event : private noncopyable { virtual ~event() = default; virtual std::unique_ptr<State> dispatch(State& s) const = 0; }; struct event_connect final : public event<state> { std::unique_ptr<state> dispatch(state& s) const override { return s.on_event(*this); } // ... }; struct event_connected final : public event<state> { std::unique_ptr<state> dispatch(state& s) const override { return s.on_event(*this); } }; struct event_disconnect final : public event<state> { std::unique_ptr<state> dispatch(state& s) const override { return s.on_event(*this); } }; struct event_timeout final : public event<state> { std::unique_ptr<state> dispatch(state& s) const override { return s.on_event(*this); } }; CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant DOUBLE DISPATCH (AKA VISITOR PATTERN) 26
  • 52. template<typename State> struct event : private noncopyable { virtual ~event() = default; virtual std::unique_ptr<State> dispatch(State& s) const = 0; }; class state : noncopyable { public: virtual ~state() = default; virtual std::unique_ptr<state> on_event(const event_connect&) { return nullptr; } virtual std::unique_ptr<state> on_event(const event_connected&) { return nullptr; } virtual std::unique_ptr<state> on_event(const event_disconnect&) { return nullptr; } virtual std::unique_ptr<state> on_event(const event_timeout&) { return nullptr; } }; CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant DOUBLE DISPATCH (AKA VISITOR PATTERN) 27
  • 53. template<typename State> struct event : private noncopyable { virtual ~event() = default; virtual std::unique_ptr<State> dispatch(State& s) const = 0; }; class state : noncopyable { public: virtual ~state() = default; virtual std::unique_ptr<state> on_event(const event_connect&) { return nullptr; } virtual std::unique_ptr<state> on_event(const event_connected&) { return nullptr; } virtual std::unique_ptr<state> on_event(const event_disconnect&) { return nullptr; } virtual std::unique_ptr<state> on_event(const event_timeout&) { return nullptr; } }; class state_idle final : public state { public: using state::on_event; std::unique_ptr<state> on_event(const event_connect& e) override { return std::make_unique<state_connecting>(std::string(e.address())); } }; CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant DOUBLE DISPATCH (AKA VISITOR PATTERN) 27
  • 54. CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant CLASS DIAGRAM 28
  • 55. template<typename State> struct event : private noncopyable { virtual ~event() = default; virtual std::unique_ptr<State> dispatch(State& s) const = 0; }; struct event_connect final : public event<state> { std::unique_ptr<state> dispatch(state& s) const override { return s.on_event(*this); } // ... }; struct event_connected final : public event<state> { std::unique_ptr<state> dispatch(state& s) const override { return s.on_event(*this); } }; struct event_disconnect final : public event<state> { std::unique_ptr<state> dispatch(state& s) const override { return s.on_event(*this); } }; struct event_timeout final : public event<state> { std::unique_ptr<state> dispatch(state& s) const override { return s.on_event(*this); } }; CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant CURIOUSLY RECURRING TEMPLATE PATTERN (CRTP) 29
  • 56. template<typename State> struct event : private noncopyable { virtual ~event() = default; virtual std::unique_ptr<State> dispatch(State& s) const = 0; }; template<typename Child> struct event_crtp : event<state> { std::unique_ptr<state> dispatch(state& s) const override { return s.on_event(*static_cast<const Child*>(this)); } }; CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant CURIOUSLY RECURRING TEMPLATE PATTERN (CRTP) 30
  • 57. template<typename State> struct event : private noncopyable { virtual ~event() = default; virtual std::unique_ptr<State> dispatch(State& s) const = 0; }; template<typename Child> struct event_crtp : event<state> { std::unique_ptr<state> dispatch(state& s) const override { return s.on_event(*static_cast<const Child*>(this)); } }; struct event_connect final : public event_crtp<event_connect> { // ... }; struct event_connected final : public event_crtp<event_connected> {}; struct event_disconnect final : public event_crtp<event_disconnect> {}; struct event_timeout final : public event_crtp<event_timeout> {}; CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant CURIOUSLY RECURRING TEMPLATE PATTERN (CRTP) 30
  • 58. template<typename State> struct event : private noncopyable { virtual ~event() = default; virtual std::unique_ptr<State> dispatch(State& s) const = 0; }; template<typename Child> struct event_crtp : event<state> { std::unique_ptr<state> dispatch(state& s) const override { return s.on_event(*static_cast<const Child*>(this)); } }; struct event_connect final : public event_crtp<event_connect> { explicit event_connect(std::string_view address): address_(address) {} std::string_view address() const { return address_; } private: std::string_view address_; }; struct event_connected final : public event_crtp<event_connected> {}; struct event_disconnect final : public event_crtp<event_disconnect> {}; struct event_timeout final : public event_crtp<event_timeout> {}; • Hey look ma, now all fits on one slide ;-) CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant CURIOUSLY RECURRING TEMPLATE PATTERN (CRTP) 31
  • 59. std::unique_ptr<state> state_idle::on_event(const event_connect& e) { } std::unique_ptr<state> state_connecting::on_event(const event_connected&) { } std::unique_ptr<state> state_connecting::on_event(const event_timeout&) { } std::unique_ptr<state> state_connected::on_event(const event_disconnect&) { } CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant TRANSITIONS 32
  • 60. std::unique_ptr<state> state_idle::on_event(const event_connect& e) { return std::make_unique<state_connecting>( std::string{e.address()}); } std::unique_ptr<state> state_connecting::on_event(const event_connected&) { } std::unique_ptr<state> state_connecting::on_event(const event_timeout&) { } std::unique_ptr<state> state_connected::on_event(const event_disconnect&) { } CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant TRANSITIONS 32
  • 61. std::unique_ptr<state> state_idle::on_event(const event_connect& e) { return std::make_unique<state_connecting>( std::string{e.address()}); } std::unique_ptr<state> state_connecting::on_event(const event_connected&) { return std::make_unique<state_connected>(); } std::unique_ptr<state> state_connecting::on_event(const event_timeout&) { } std::unique_ptr<state> state_connected::on_event(const event_disconnect&) { } CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant TRANSITIONS 32
  • 62. std::unique_ptr<state> state_idle::on_event(const event_connect& e) { return std::make_unique<state_connecting>( std::string{e.address()}); } std::unique_ptr<state> state_connecting::on_event(const event_connected&) { return std::make_unique<state_connected>(); } std::unique_ptr<state> state_connecting::on_event(const event_timeout&) { return ++n < n_max ? nullptr : std::make_unique<state_idle>(); } std::unique_ptr<state> state_connected::on_event(const event_disconnect&) { } CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant TRANSITIONS 32
  • 63. std::unique_ptr<state> state_idle::on_event(const event_connect& e) { return std::make_unique<state_connecting>( std::string{e.address()}); } std::unique_ptr<state> state_connecting::on_event(const event_connected&) { return std::make_unique<state_connected>(); } std::unique_ptr<state> state_connecting::on_event(const event_timeout&) { return ++n < n_max ? nullptr : std::make_unique<state_idle>(); } std::unique_ptr<state> state_connected::on_event(const event_disconnect&) { return std::make_unique<state_idle>(); } CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant TRANSITIONS 32
  • 64. std::unique_ptr<state> state_idle::on_event(const event_connect& e) { return std::make_unique<state_connecting>( std::string{e.address()}); } std::unique_ptr<state> state_connecting::on_event(const event_connected&) { return std::make_unique<state_connected>(); } std::unique_ptr<state> state_connecting::on_event(const event_timeout&) { return ++n < n_max ? nullptr : std::make_unique<state_idle>(); } std::unique_ptr<state> state_connected::on_event(const event_disconnect&) { return std::make_unique<state_idle>(); } CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant THE SLOW PART 33
  • 65. template<typename Fsm, typename... Events> void dispatch(Fsm& fsm, const Events&... events) { (fsm.dispatch(*events), ...); } CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant TESTING TRANSITIONS 34
  • 66. template<typename Fsm, typename... Events> void dispatch(Fsm& fsm, const Events&... events) { (fsm.dispatch(*events), ...); } dispatch(fsm, std::make_unique<event_connect>("train-it.eu"), std::make_unique<event_timeout>(), std::make_unique<event_connected>(), std::make_unique<event_disconnect>()); CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant TESTING TRANSITIONS 34
  • 67. template<typename Fsm, typename... Events> void dispatch(Fsm& fsm, const Events&... events) { (fsm.dispatch(*events), ...); } dispatch(fsm, std::make_unique<event_connect>("train-it.eu"), std::make_unique<event_timeout>(), std::make_unique<event_connected>(), std::make_unique<event_disconnect>()); CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant THE SLOW PART 35
  • 68. • Open to new alternatives • Closed to new alternatives – one of class hierarchies fixed at design time and cannot be extended by clients • Closed to new operations – clients cannot add new operations to dynamic dispatch • Multi-level – many levels of inheritance possible • Object Oriented – whole framework is based on objects CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant DOUBLE DYNAMIC DISPATCH (AKA VISITOR PATTERN) 36
  • 69. std:variant IN 3 MINUTES
  • 70. template<class... Types> class variant; • Represents a type-safe union • At any given point in time either – holds a value of one of its alternative types – is in special valueless_by_exception state (reached if an exception is thrown during contained value initialization or assignment) CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant std::variant<Types...> 38
  • 71. // not a valid C++ template<typename Type1, typename Type2, typename Type3...> class variant { union options { Type1 t1; Type2 t2; Type3 t3; ... }; int index_; public: variant(); template<class T> variant(T&& t); template<class T, class... Args> variant(std::in_place_type_t<T>, Args&&... args); std::size_t index() const; //... }; CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant std::variant<Types...> INTERFACE (SIMPLIFICATION) 39
  • 72. • Not allowed to allocate dynamic memory • Not permitted to hold references, arrays, or void • Empty variants are ill-formed (std::variant<std::monostate> can be used instead) • Permitted to hold the same type more than once, and to hold di erently cv-qualified versions of the same type • Default-initialized variant holds a value of its first alternative unless that alternative is not default- constructible CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant std::variant<Types...> 40
  • 73. void print(const std::variant<int, double, X>& v) { switch (v.index()) { case 0: std::cout << "int: " << std::get<0>(v) << 'n'; break; case 1: std::cout << "double: " << std::get<1>(v) << 'n'; break; case 2: std::cout << "X: " << std::get<2>(v).x << ", " << std::get<2>(v).y << 'n'; break; } } CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant std::variant<Types...> 41
  • 74. void print(const std::variant<int, double, X>& v) { switch (v.index()) { case 0: std::cout << "int: " << std::get<0>(v) << 'n'; break; case 1: std::cout << "double: " << std::get<1>(v) << 'n'; break; case 2: std::cout << "X: " << std::get<2>(v).x << ", " << std::get<2>(v).y << 'n'; break; } } struct visitor { void operator()(int v) const { std::cout << "int: " << v << 'n'; } void operator()(double v) const { std::cout << "double: " << v << 'n'; } void operator()(const X& v) const { std::cout << "X: " << v.x << ", " << v.y << 'n'; } }; void print(const std::variant<int, double, X>& v) { std::visit(visitor{}, v); } CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant std::variant<Types...> 41
  • 75. VARIANT + EXTERNAL TRANSITIONS CASE #3
  • 76. struct event_connect { std::string_view address; }; struct event_connected {}; struct event_disconnect {}; struct event_timeout {}; using event = std::variant<event_connect, event_connected, event_disconnect, event_timeout>; CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant EVENTS AND STATES EVENTS 43
  • 77. struct event_connect { std::string_view address; }; struct event_connected {}; struct event_disconnect {}; struct event_timeout {}; using event = std::variant<event_connect, event_connected, event_disconnect, event_timeout>; struct state_idle {}; struct state_connecting { static constexpr int n_max = 3; int n = 0; std::string address; }; struct state_connected {}; using state = std::variant<state_idle, state_connecting, state_connected>; CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant EVENTS AND STATES EVENTS STATES 43
  • 78. struct transitions { optional<state> operator()(state_idle&, const event_connect& e) { } optional<state> operator()(state_connecting&, const event_connected&) { } optional<state> operator()(state_connecting& s, const event_timeout&) { } optional<state> operator()(state_connected&, const event_disconnect&) { } }; CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant TRANSITIONS 44
  • 79. struct transitions { optional<state> operator()(state_idle&, const event_connect& e) { return state_connecting{std::string(e.address)}; } optional<state> operator()(state_connecting&, const event_connected&) { } optional<state> operator()(state_connecting& s, const event_timeout&) { } optional<state> operator()(state_connected&, const event_disconnect&) { } }; CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant TRANSITIONS 44
  • 80. struct transitions { optional<state> operator()(state_idle&, const event_connect& e) { return state_connecting{std::string(e.address)}; } optional<state> operator()(state_connecting&, const event_connected&) { return state_connected{}; } optional<state> operator()(state_connecting& s, const event_timeout&) { } optional<state> operator()(state_connected&, const event_disconnect&) { } }; CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant TRANSITIONS 44
  • 81. struct transitions { optional<state> operator()(state_idle&, const event_connect& e) { return state_connecting{std::string(e.address)}; } optional<state> operator()(state_connecting&, const event_connected&) { return state_connected{}; } optional<state> operator()(state_connecting& s, const event_timeout&) { return ++s.n < state_connecting::n_max ? std::nullopt : optional<state>(state_idle{}); } optional<state> operator()(state_connected&, const event_disconnect&) { } }; CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant TRANSITIONS 44
  • 82. struct transitions { optional<state> operator()(state_idle&, const event_connect& e) { return state_connecting{std::string(e.address)}; } optional<state> operator()(state_connecting&, const event_connected&) { return state_connected{}; } optional<state> operator()(state_connecting& s, const event_timeout&) { return ++s.n < state_connecting::n_max ? std::nullopt : optional<state>(state_idle{}); } optional<state> operator()(state_connected&, const event_disconnect&) { return state_idle{}; } }; CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant TRANSITIONS 44
  • 83. struct transitions { optional<state> operator()(state_idle&, const event_connect& e) { return state_connecting{std::string(e.address)}; } optional<state> operator()(state_connecting&, const event_connected&) { return state_connected{}; } optional<state> operator()(state_connecting& s, const event_timeout&) { return ++s.n < state_connecting::n_max ? std::nullopt : optional<state>(state_idle{}); } optional<state> operator()(state_connected&, const event_disconnect&) { return state_idle{}; } template<typename State, typename Event> optional<state> operator()(State&, const Event&) const { return std::nullopt; } }; CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant TRANSITIONS 44
  • 84. template<typename StateVariant, typename EventVariant, typename Transitions> class fsm { StateVariant state_; public: void dispatch(const EventVariant& event) { std::optional<StateVariant> new_state = std::visit(Transitions{}, state_, event); if(new_state) state_ = *std::move(new_state); } }; using connection_fsm = fsm<state, event, transitions>; CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant FSM ENGINE 45
  • 85. template<typename StateVariant, typename EventVariant, typename Transitions> class fsm { StateVariant state_; public: void dispatch(const EventVariant& event) { std::optional<StateVariant> new_state = std::visit(Transitions{}, state_, event); if(new_state) state_ = *std::move(new_state); } }; using connection_fsm = fsm<state, event, transitions>; CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant FSM ENGINE 46
  • 86. template<typename StateVariant, typename EventVariant, typename Transitions> class fsm { StateVariant state_; public: void dispatch(const EventVariant& event) { std::optional<StateVariant> new_state = std::visit(Transitions{}, state_, event); if(new_state) state_ = *std::move(new_state); } }; using connection_fsm = fsm<state, event, transitions>; CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant FSM ENGINE 47
  • 87. CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant CLASS DIAGRAM 48
  • 88. template<typename Fsm, typename... Events> void dispatch(Fsm& fsm, Events&&... events) { (fsm.dispatch(std::forward<Events>(events)), ...); } dispatch(fsm, event_connect{"train-it.eu"}, event_timeout{}, event_connected{}, event_disconnect{}); CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant TESTING TRANSITIONS 49
  • 89. VARIANT + TRANSITIONS IN FSM CASE #4
  • 90. template<typename Derived, typename StateVariant, typename EventVariant> class fsm { StateVariant state_; public: void dispatch(const EventVariant& event) { auto new_state = std::visit( state_, event); if(new_state) state_ = *std::move(new_state); } }; CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant FSM ENGINE 51
  • 91. template<typename Derived, typename StateVariant, typename EventVariant> class fsm { StateVariant state_; public: void dispatch(const EventVariant& event) { Derived& child = static_cast<Derived&>(*this); auto new_state = std::visit( [&](auto& s, const auto& e) -> std::optional<StateVariant> { return child.on_event(s, e); }, state_, event); if(new_state) state_ = *std::move(new_state); } }; • CRTP again ;-) CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant FSM ENGINE 51
  • 92. template<typename Derived, typename StateVariant> class fsm { StateVariant state_; public: template<typename Event> void dispatch(Event&& event) { Derived& child = static_cast<Derived&>(*this); auto new_state = std::visit( [&](auto& s) -> std::optional<StateVariant> { return child.on_event(s, std::forward<Event>(event)); }, state_); if(new_state) state_ = *std::move(new_state); } }; • Variant of events not needed anymore CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant FSM ENGINE 52
  • 93. class connection_fsm : public fsm<connection_fsm, state> { public: auto on_event(state_idle&, const event_connect& e) { } auto on_event(state_connecting&, const event_connected&) { } auto on_event(state_connecting& s, const event_timeout&) { } auto on_event(state_connected&, const event_disconnect&) { } template<typename State, typename Event> auto on_event(State&, const Event&) { } }; CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant TRANSITIONS DEFINED BY THE FSM ITSELF 53
  • 94. class connection_fsm : public fsm<connection_fsm, state> { public: auto on_event(state_idle&, const event_connect& e) { return state_connecting{std::string(e.address)}; } auto on_event(state_connecting&, const event_connected&) { return state_connected{}; } auto on_event(state_connecting& s, const event_timeout&) { return ++s.n < state_connecting::n_max ? std::nullopt : std::optional<state>(state_idle{}); } auto on_event(state_connected&, const event_disconnect&) { return state_idle{}; } template<typename State, typename Event> auto on_event(State&, const Event&) { return std::nullopt; } }; CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant TRANSITIONS DEFINED BY THE FSM ITSELF 53
  • 95. CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant CLASS DIAGRAM 54
  • 96. VARIANT + TRANSITIONS IN STATES CASE #5
  • 97. template<typename StateVariant, typename OnInvalidTransition> class fsm { StateVariant state_; public: template<typename Event> void dispatch(Event&& event) { auto new_state = std::visit(overloaded{ }, state_); if(new_state) state_ = *std::move(new_state); } }; • Beware, lambdas are coming :-) CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant FSM ENGINE 56
  • 98. template<typename StateVariant, typename OnInvalidTransition> class fsm { StateVariant state_; public: template<typename Event> void dispatch(Event&& event) { auto new_state = std::visit(overloaded{ [&](auto& s, decltype(s.on_event(event))* = nullptr) -> std::optional<StateVariant> { return s.on_event(std::forward<Event>(event)); }, }, state_); if(new_state) state_ = *std::move(new_state); } }; • Thanks to SFINAE matches defined transitions only CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant FSM ENGINE 57
  • 99. template<typename StateVariant, typename OnInvalidTransition> class fsm { StateVariant state_; public: template<typename Event> void dispatch(Event&& event) { auto new_state = std::visit(overloaded{ [&](auto& s, decltype(s.on_event(event))* = nullptr) -> std::optional<StateVariant> { return s.on_event(std::forward<Event>(event)); }, [&](auto&... s) -> std::optional<StateVariant> { return OnInvalidTransition()(s..., std::forward<Event>(event)); } }, state_); if(new_state) state_ = *std::move(new_state); } }; • Worse overload thanks to a template parameter pack usage CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant FSM ENGINE 58
  • 100. auto state_idle::on_event(const event_connect& e) { return state_connecting{std::string(e.address)}; } auto state_connecting::on_event(const event_connected&) { return state_connected{}; } auto state_connecting::on_event(const event_timeout&) { return ++n_ < n_max ? std::nullopt : std::optional<state>(state_idle{}); } auto state_connected::on_event(const event_disconnect&) { return state_idle{}; } CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant TRANSITIONS DEFINED BY STATES 59
  • 101. auto state_idle::on_event(const event_connect& e) { return state_connecting{std::string(e.address)}; } auto state_connecting::on_event(const event_connected&) { return state_connected{}; } auto state_connecting::on_event(const event_timeout&) { return ++n_ < n_max ? std::nullopt : std::optional<state>(state_idle{}); } auto state_connected::on_event(const event_disconnect&) { return state_idle{}; } struct ignore_unknown_event { template<typename State, typename Event> auto operator()(const State&, const Event&) { return std::nullopt; } }; CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant TRANSITIONS DEFINED BY STATES 59
  • 103. CLOSED(Start) LISTEN/- CLOSE/- LISTEN SYN RECEIVED SYN SENT CONNECT/ (Step 1 of the 3-way-handshake)SYN SYN/SYN+ACK(Step 2 of the 3-way-handshake) unusual event client/receiver path server/sender path RST/- SYN/SYN+ACK (simultaneous open) SYN+ACK/ACK (Step 3 of the 3-way-handshake) Data exchange occurs ESTABLISHED FIN/ACK ACK/- CLOSE/- SEND/SYN CLOSE/FIN CLOSE/FIN CLOSING TIME WAIT CLOSED FIN WAIT 1 FIN WAIT 2 CLOSE WAIT LAST ACK CLOSE/FIN FIN/ACK FIN+ACK/ACK ACK/- FIN/ACK Timeout (Go back to start) Active CLOSE Passive CLOSE ACK/- ACK/- CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant TCP STATE DIAGRAM 61
  • 104. CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant TCP FSM PERFORMANCE 62
  • 105. CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant TCP FSM PERFORMANCE 62
  • 106. CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant TCP FSM PERFORMANCE 62
  • 108. CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant std::variant<Types...> VS INHERITANCE INHERITANCE VARIANT 64
  • 109. • Open/Closed to new alternatives • Closed to new alternatives CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant std::variant<Types...> VS INHERITANCE INHERITANCE VARIANT 64
  • 110. • Open/Closed to new alternatives • Closed to new operations • Closed to new alternatives • Open to new operations CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant std::variant<Types...> VS INHERITANCE INHERITANCE VARIANT 64
  • 111. • Open/Closed to new alternatives • Closed to new operations • Multi-level • Closed to new alternatives • Open to new operations • Single level CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant std::variant<Types...> VS INHERITANCE INHERITANCE VARIANT 64
  • 112. • Open/Closed to new alternatives • Closed to new operations • Multi-level • OO • Closed to new alternatives • Open to new operations • Single level • Functional CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant std::variant<Types...> VS INHERITANCE INHERITANCE VARIANT 64
  • 113. • Open/Closed to new alternatives • Closed to new operations • Multi-level • OO • Pointer semantics • Closed to new alternatives • Open to new operations • Single level • Functional • Value semantics CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant std::variant<Types...> VS INHERITANCE INHERITANCE VARIANT 64
  • 114. • Open/Closed to new alternatives • Closed to new operations • Multi-level • OO • Pointer semantics • Design forced by the implementation details • Closed to new alternatives • Open to new operations • Single level • Functional • Value semantics • Many design choices possible CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant std::variant<Types...> VS INHERITANCE INHERITANCE VARIANT 64
  • 115. • Open/Closed to new alternatives • Closed to new operations • Multi-level • OO • Pointer semantics • Design forced by the implementation details • Forces dynamic memory allocations • Closed to new alternatives • Open to new operations • Single level • Functional • Value semantics • Many design choices possible • No dynamic memory allocations CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant std::variant<Types...> VS INHERITANCE INHERITANCE VARIANT 64
  • 116. • Open/Closed to new alternatives • Closed to new operations • Multi-level • OO • Pointer semantics • Design forced by the implementation details • Forces dynamic memory allocations • Strict interfaces • Closed to new alternatives • Open to new operations • Single level • Functional • Value semantics • Many design choices possible • No dynamic memory allocations • Duck typing CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant std::variant<Types...> VS INHERITANCE INHERITANCE VARIANT 64
  • 117. • Open/Closed to new alternatives • Closed to new operations • Multi-level • OO • Pointer semantics • Design forced by the implementation details • Forces dynamic memory allocations • Strict interfaces • Complex • Closed to new alternatives • Open to new operations • Single level • Functional • Value semantics • Many design choices possible • No dynamic memory allocations • Duck typing • Simple CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant std::variant<Types...> VS INHERITANCE INHERITANCE VARIANT 64
  • 118. • Open/Closed to new alternatives • Closed to new operations • Multi-level • OO • Pointer semantics • Design forced by the implementation details • Forces dynamic memory allocations • Strict interfaces • Complex • Slower • Closed to new alternatives • Open to new operations • Single level • Functional • Value semantics • Many design choices possible • No dynamic memory allocations • Duck typing • Simple • Faster CppCon 2018 | E ective replacement of dynamic polymorphism with std::variant std::variant<Types...> VS INHERITANCE INHERITANCE VARIANT 64