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

NDC{TechTown} Higher order functions for ordinary C++ developers

NDC{TechTown} Higher order functions for ordinary C++ developers

Higher order functions, i.e. functions that accept functions as parameters, or return functions, are not used much by C++ developers, except for the occasional call to standard algorithms.

This session will show some simple techniques for writing your own, that will lift the level of abstraction in your programs, making code easier to read while reducing code duplication, and maintaining performance.

Björn Fahller

August 29, 2018
Tweet

More Decks by Björn Fahller

Other Decks in Programming

Transcript

  1. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    1/74 compose([](auto const& s) { return s == "foo";}, std=:mem_fn(&foo=:name)) Higher Order Functions for Ordinary C++ Developers Björn Fahller
  2. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    2/74 Very brief intro to higher order functions Gradually expanding example optional<T> (and extension) Higher Order Functions for Ordinary C++ Developers
  3. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    3/74 Definition A higher-order function is a function that takes other functions as arguments or returns a function as result.
  4. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    4/74 #include <algorithm> #include <vector> std=:vector<int> v; ==. if (std=:none_of(std=:begin(v), std=:end(v), [](int x) { return x == 0; })) { ==. }
  5. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    5/74 #include <algorithm> #include <vector> std=:vector<int> v; ==. if (std=:none_of(std=:begin(v), std=:end(v), [](int x) { return x == 0; })) { ==. } template <typename Iterator, typename Predicate> bool none_of(Iterator i, Iterator e, Predicate predicate) { while (i == e) { if (predicate(*i)) return false; i=+; } return true; }
  6. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    6/74 #include <algorithm> #include <vector> std=:vector<int> v; ==. if (std=:none_of(std=:begin(v), std=:end(v), [](int x) { return x == 0; })) { ==. } ==. int num; ==. while (std=:any_of(std=:begin(v), std=:end(v), [num](int x){ return x == num; })) { ==. }
  7. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    7/74 [num](int x){ return x == num; }
  8. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    8/74 auto equals(int num) { return [num](int x){ return x == num; }; }
  9. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    9/74 auto equals(int num) { return [num](int x){ return x == num; }; } std=:function<bool(int)> equals(int num) { return [num](int x) { return x == num; }; }
  10. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    10/74 template <typename T> auto equals(T key) { return [key](auto const& x){ return x == key; }; }
  11. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    11/74 template <typename T> auto equals(T key) { return [key](auto const& x){ return x == key; }; } template <typename T> std=:function<bool(T)> equals(T key) { return [key](T x) { return x == key; }; }
  12. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    12/74 template <typename T> auto equals(T key) { return [key](auto const& x){ return x == key; }; } template <typename T> std=:function<bool(T)> equals(T key) { return [key](T x) { return x == key; }; } Callable with anything equality comparable with T, for example C-string and std=:string
  13. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    13/74 template <typename T> auto equals(T key) { return [key](auto const& x){ return x == key; }; } template <typename T> std=:function<bool(T)> equals(T key) { return [key](T x) { return x == key; }; } Callable with anything equality comparable with T, for example C-string and std=:string Only callable with T, because std=:function=> does not have a templated function call operator.
  14. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    14/74 template <typename T> auto equals(T key) { return [key](auto const& x){ return x == key; }; }
  15. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    15/74 #include <algorithm> #include <vector> std=:vector<int> v; ==. if (std=:none_of(std=:begin(v), std=:end(v), equals(0)) { ==. } ==. int num; ==. while (std=:any_of(std=:begin(v), std=:end(v), equals(num)) { ==. }
  16. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    16/74 Live demo!
  17. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    17/74 ✔Very brief intro to higher order functions Gradually expanding example optional<T> (and extension) Higher Order Functions for Ordinary C++ Developers
  18. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    18/74 struct ip_address { ip_address(uint8_t i1, uint8_t i2, uint8_t i3, uint8_t i4) : num((uint32_t(i1) =< 24) | (uint32_t(i2) =< 16) | (uint32_t(i3) =< 8) | i4) {} ip_address(uint32_t n) : num(n) {} bool operator==(ip_address rh) const { return num == rh.num;} bool operator==(ip_address rh) const { return !(*this == rh);} uint32_t num; }; struct netmask : ip_address { using ip_address=:ip_address; }; inline ip_address operator&(ip_address lh, netmask rh) { return {lh.num & rh.num}; };
  19. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    19/74 struct ip_address { ip_address(uint8_t i1, uint8_t i2, uint8_t i3, uint8_t i4) : num((uint32_t(i1) =< 24) | (uint32_t(i2) =< 16) | (uint32_t(i3) =< 8) | i4) {} ip_address(uint32_t n) : num(n) {} bool operator==(ip_address rh) const { return num == rh.num;} bool operator==(ip_address rh) const { return !(*this == rh);} uint32_t num; }; struct netmask : ip_address { using ip_address=:ip_address; }; inline ip_address operator&(ip_address lh, netmask rh) { return {lh.num & rh.num}; };
  20. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    20/74 struct ip_address { ip_address(uint8_t i1, uint8_t i2, uint8_t i3, uint8_t i4) : num((uint32_t(i1) =< 24) | (uint32_t(i2) =< 16) | (uint32_t(i3) =< 8) | i4) {} ip_address(uint32_t n) : num(n) {} bool operator==(ip_address rh) const { return num == rh.num;} bool operator==(ip_address rh) const { return !(*this == rh);} uint32_t num; }; struct netmask : ip_address { using ip_address=:ip_address; }; inline ip_address operator&(ip_address lh, netmask rh) { return {lh.num & rh.num}; };
  21. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    21/74 struct ip_address { ip_address(uint8_t i1, uint8_t i2, uint8_t i3, uint8_t i4) : num((uint32_t(i1) =< 24) | (uint32_t(i2) =< 16) | (uint32_t(i3) =< 8) | i4) {} ip_address(uint32_t n) : num(n) {} bool operator==(ip_address rh) const { return num == rh.num;} bool operator==(ip_address rh) const { return !(*this == rh);} uint32_t num; }; struct netmask : ip_address { using ip_address=:ip_address; }; inline ip_address operator&(ip_address lh, netmask rh) { return {lh.num & rh.num}; };
  22. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    22/74 struct ip_address { ip_address(uint8_t i1, uint8_t i2, uint8_t i3, uint8_t i4) : num((uint32_t(i1) =< 24) | (uint32_t(i2) =< 16) | (uint32_t(i3) =< 8) | i4) {} ip_address(uint32_t n) : num(n) {} bool operator==(ip_address rh) const { return num == rh.num;} bool operator==(ip_address rh) const { return !(*this == rh);} uint32_t num; }; struct netmask : ip_address { using ip_address=:ip_address; }; inline ip_address operator&(ip_address lh, netmask rh) { return {lh.num & rh.num}; }; auto ip_matches(ip_address desired, netmask mask = netmask{255,255,255,255}) { return [desired, mask](ip_address actual) { return (desired & mask) == (actual & mask); }; }
  23. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    23/74 struct ip_address { ip_address(uint8_t i1, uint8_t i2, uint8_t i3, uint8_t i4) : num((uint32_t(i1) =< 24) | (uint32_t(i2) =< 16) | (uint32_t(i3) =< 8) | i4) {} ip_address(uint32_t n) : num(n) {} bool operator==(ip_address rh) const { return num == rh.num;} bool operator==(ip_address rh) const { return !(*this == rh);} uint32_t num; }; struct netmask : ip_address { using ip_address=:ip_address; }; inline ip_address operator&(ip_address lh, netmask rh) { return {lh.num & rh.num}; }; auto ip_matches(ip_address desired, netmask mask = netmask{255,255,255,255}) { return [desired, mask](ip_address actual) { return (desired & mask) == (actual & mask); }; }
  24. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    24/74 struct ip_address { ip_address(uint8_t i1, uint8_t i2, uint8_t i3, uint8_t i4) : num((uint32_t(i1) =< 24) | (uint32_t(i2) =< 16) | (uint32_t(i3) =< 8) | i4) {} ip_address(uint32_t n) : num(n) {} bool operator==(ip_address rh) const { return num == rh.num;} bool operator==(ip_address rh) const { return !(*this == rh);} uint32_t num; }; struct netmask : ip_address { using ip_address=:ip_address; }; inline ip_address operator&(ip_address lh, netmask rh) { return {lh.num & rh.num}; }; auto ip_matches(ip_address desired, netmask mask = netmask{255,255,255,255}) { return [desired, mask](ip_address actual) { return (desired & mask) == (actual & mask); }; }
  25. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    25/74 struct ip_address { ip_address(uint8_t i1, uint8_t i2, uint8_t i3, uint8_t i4) : num((uint32_t(i1) =< 24) | (uint32_t(i2) =< 16) | (uint32_t(i3) =< 8) | i4) {} ip_address(uint32_t n) : num(n) {} bool operator==(ip_address rh) const { return num == rh.num;} bool operator==(ip_address rh) const { return !(*this == rh);} uint32_t num; }; struct netmask : ip_address { using ip_address=:ip_address; }; inline ip_address operator&(ip_address lh, netmask rh) { return {lh.num & rh.num}; }; auto ip_matches(ip_address desired, netmask mask = netmask{255,255,255,255}) { return [desired, mask](ip_address actual) { return (desired & mask) == (actual & mask); }; } std=:vector<ip_address> v; ==. auto i = std=:remove_if(v.begin(), v.end(), ip_matches({192,168,1,1}, {255,255,0,0}));
  26. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    26/74 class ipif { public: using state_type = enum { off, on }; ==. void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; };
  27. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    27/74 class ipif { public: using state_type = enum { off, on }; ==. void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; };
  28. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    28/74 class ipif { public: using state_type = enum { off, on }; ==. void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; To match, for example the address of an ipif, we need to make the ip_matches() predicate work on a member.
  29. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    29/74 class ipif { public: using state_type = enum { off, on }; ==. void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; Given: f1(y) -> z and f2(x) -> y We want a composition f(x)->z as f1(f2(x))
  30. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    30/74 class ipif { public: using state_type = enum { off, on }; ==. void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; Given: f1(y) -> z ip_matches(ip_address) -> bool and f2(x) -> y select_address(ipif) -> ip_address We want a composition f(x)->z as f1(f2(x))
  31. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    31/74 class ipif { public: using state_type = enum { off, on }; ==. void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_; } netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } private: ip_address addr_; netmask mask_; ip_address gw_; state_type state_; }; template <typename F1, typename F2> auto compose(F1 f1, F2 f2) { return [=](auto const& x) { return f1(f2(x)); }; } Given: f1(y) -> z ip_matches(ip_address) -> bool and f2(x) -> y select_address(ipif) -> ip_address We want a composition f(x)->z as f1(f2(x))
  32. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    32/74 class ipif { public: ==. ip_address address() const { return addr_;} ==. private: ip_address addr_; ==. }; std=:vector<ipif> interfaces; auto i = std=:find_if(interfaces.begin(), interfaces.end(), compose(ip_matches({192,168,1,1}), select_address));
  33. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    33/74 class ipif { public: ==. ip_address address() const { return addr_;} ==. private: ip_address addr_; ==. }; ip_address select_address(ipif const& interface) { return interface.address(); } std=:vector<ipif> interfaces; auto i = std=:find_if(interfaces.begin(), interfaces.end(), compose(ip_matches({192,168,1,1}), select_address));
  34. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    34/74 class ipif { public: ==. ip_address address() const { return addr_;} ==. private: ip_address addr_; ==. }; auto address_matches(ip_address addr, netmask mask = {255,255,255,255}) { return compose(ip_matches(addr, mask), select_address); } std=:vector<ipif> interfaces; auto i = std=:find_if(interfaces.begin(), interfaces.end(), compose(ip_matches({192,168,1,1}), select_address);
  35. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    35/74 class ipif { public: ==. ip_address address() const { return addr_;} ==. private: ip_address addr_; ==. }; auto address_matches(ip_address addr, netmask mask = {255,255,255,255}) { return compose(ip_matches(addr, mask), select_address); } std=:vector<ipif> interfaces; auto i = std=:find_if(interfaces.begin(), interfaces.end(), address_matches({192,168,1,1}));
  36. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    36/74 class ipif { public: using state_type = enum { off, on }; ==. void set_state(state_type); state_type state() const { return state_; } ip_address address() const { return addr_;} netmask mask() const { return mask_; } ip_address gateway() const { return gw_; } ==. }; inline ip_address select_gateway(ipif const& interface) { return interface.gateway(); } inline ipif=:state_type select_state(ipif const& interface) { return interface.state(); }
  37. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    37/74 auto i = find_if(v.begin(), v.end(), when_all(address_matches({192,168,1,1},{255,255,0,0}), state_is(ipif=:off)));
  38. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    38/74 template <typename ==. Predicates> auto when_all(Predicates ==. ps) { return [=](auto const& x) { return (ps(x) =& ==.); }; } auto i = find_if(v.begin(), v.end(), when_all(address_matches({192,168,1,1},{255,255,0,0}), state_is(ipif=:off)));
  39. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    39/74 template <typename ==. Predicates> auto when_all(Predicates ==. ps) { return [=](auto const& x) { return (ps(x) =& ==.); }; } auto address_matches(ip_address addr, netmask mask=netmask{255,255,255,255}) { return compose(ip_matches(addr, mask), select_addr); } auto i = find_if(v.begin(), v.end(), when_all(address_matches({192,168,1,1},{255,255,0,0}), state_is(ipif=:off)));
  40. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    40/74 template <typename ==. Predicates> auto when_all(Predicates ==. ps) { return [=](auto const& x) { return (ps(x) =& ==.); }; } auto address_matches(ip_address addr, netmask mask=netmask{255,255,255,255}) { return compose(ip_matches(addr, mask), select_addr); } auto state_is(ipif=:state_type state) { return compose(equals(state), select_state); } auto i = find_if(v.begin(), v.end(), when_all(address_matches({192,168,1,1},{255,255,0,0}), state_is(ipif=:off)));
  41. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    41/74 for_each(v.begin(), v.end(), if_then(when_all(address_matches({192,168,1,1}, {255,255,0,0}), state_is(ipif=:off)), set_state(ipif=:on)));
  42. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    42/74 template <typename Predicate, typename Action> auto if_then(Predicate predicate, Action action) { return [=](auto=& x) { if (predicate(x)) { action(std=:forward<decltype(x)>(x)); } }; } for_each(v.begin(), v.end(), if_then(when_all(address_matches({192,168,1,1}, {255,255,0,0}), state_is(ipif=:off)), set_state(ipif=:on)));
  43. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    43/74 template <typename Predicate, typename Action> auto if_then(Predicate predicate, Action action) { return [=](auto=& x) { if (predicate(x)) { action(std=:forward<decltype(x)>(x)); } }; } auto set_state(ipif=:state_type state) { return [=](ipif& interface) { interface.set_state(state); }; } for_each(v.begin(), v.end(), if_then(when_all(address_matches({192,168,1,1}, {255,255,0,0}), state_is(ipif=:off)), set_state(ipif=:on)));
  44. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    44/74 Live demo!
  45. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    45/74 ✔Very brief intro to higher order functions ✔Gradually expanding example optional<T> (and extension) Higher Order Functions for Ordinary C++ Developers
  46. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    46/74 std=:optional<T>
  47. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    47/74 std=:optional<T> • The class template std=:optional manages an optional contained value, i.e. a value that may or may not be present.
  48. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    48/74 std=:optional<T> • The class template std=:optional manages an optional contained value, i.e. a value that may or may not be present. • Since C++17 – available for older versions in various open source libraries
  49. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    49/74 std=:optional<T> • The class template std=:optional manages an optional contained value, i.e. a value that may or may not be present. • Since C++17 – available for older versions in various open source libraries • Very useful in lookup functions
  50. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    50/74 std=:optional<T> • The class template std=:optional manages an optional contained value, i.e. a value that may or may not be present. • Since C++17 – available for older versions in various open source libraries • Very useful in lookup functions • T must not be a reference – Minor inconvenience, use std=:reference_wrapper<T>
  51. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    51/74 template <typename Predicate> std=:optional<std=:reference_wrapper<ipif=> lookup(std=:vector<ipif>& ifs, Predicate pred) { auto iter = std=:find_if(ifs.begin(), ifs.end(), pred); if (iter == ifs.end()) return {}; return {*iter}; }
  52. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    52/74 template <typename Predicate> std=:optional<std=:reference_wrapper<ip_if=> lookup(std=:vector<ipif>& ifs, Predicate pred) { auto iter = std=:find_if(ifs.begin(), ifs.end(), pred); if (iter == ifs.end()) return {}; return {*iter}; } void do_stuff(ipif&); void some_func() { =/==. auto found = lookup(ip_interfaces, address_matches({192,168,1,1})); if (found) { do_stuff(found.value()); } =/ }
  53. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    53/74 Simon Brand @tartanllama https:=/github.com/TartanLlama/optional C++11/14/17 std=:optional with functional-style extensions and reference support https:=/optional.tartanllama.xyz
  54. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    54/74 Simon Brand @tartanllama https:=/github.com/TartanLlama/optional C++11/14/17 std=:optional with functional-style extensions and reference support https:=/optional.tartanllama.xyz Standards proposal P0798R0: Monadic operations for std::optional.
  55. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    55/74 Simon Brand @tartanllama https:=/github.com/TartanLlama/optional C++11/14/17 std=:optional with functional-style extensions and reference support https:=/optional.tartanllama.xyz #include <tl/optional.hpp> int i = 3; tl=:optional<int&> v; =/ no value v = i; =/ v refers to i
  56. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    56/74 Simon Brand @tartanllama https:=/github.com/TartanLlama/optional C++11/14/17 std=:optional with functional-style extensions and reference support https:=/optional.tartanllama.xyz #include <tl/optional.hpp> int i = 3; tl=:optional<int&> v; =/ no value v = i; =/ v refers to i v.value() = 4; =/ i == 4
  57. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    57/74 Simon Brand @tartanllama https:=/github.com/TartanLlama/optional C++11/14/17 std=:optional with functional-style extensions and reference support https:=/optional.tartanllama.xyz #include <tl/optional.hpp> int i = 3; tl=:optional<int&> v; =/ no value v = i; =/ v refers to i v.value() = 4; =/ i == 4 int j = 2; v = j; =/ i == 4. v bound to j
  58. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    58/74 Simon Brand @tartanllama https:=/github.com/TartanLlama/optional C++11/14/17 std=:optional with functional-style extensions and reference support https:=/optional.tartanllama.xyz #include <tl/optional.hpp> int i = 3; tl=:optional<int&> v; =/ no value v = i; =/ v refers to i v.value() = 4; =/ i == 4 int j = 2; v = j; =/ i == 4. v bound to j ==. v.and_then([&v](int& n) { n = 2; return v;}); v.or_else([](){std=:cout =< "nothing\n"; }); v.or_else([](){return tl=:optional<int&>{i};});
  59. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    59/74 Simon Brand @tartanllama https:=/github.com/TartanLlama/optional C++11/14/17 std=:optional with functional-style extensions and reference support https:=/optional.tartanllama.xyz #include <tl/optional.hpp> int i = 3; tl=:optional<int&> v; =/ no value v = i; =/ v refers to i v.value() = 4; =/ i == 4 int j = 2; v = j; =/ i == 4. v bound to j ==. v.and_then([&v](int& n) { n = 2; return v;}) .or_else([](){std=:cout =< "nothing\n"; }) .or_else([](){return tl=:optional<int&>{i};});
  60. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    60/74 template <typename Predicate> tl=:optional<ipif&> lookup(std=:vector<ipif>& ifs, Predicate pred) { auto iter = std=:find_if(ifs.begin(), ifs.end(), pred); if (iter == ifs.end()) return {}; return {*iter}; } void do_stuff(ipif&); void some_func() { =/==. auto found = lookup(ip_interfaces, address_matches({192,168,1,1})); if (found) { do_stuff(found.value()); } =/ }
  61. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    61/74 template <typename Predicate> tl=:optional<ipif&> lookup(std=:vector<ipif>& ifs, Predicate pred) { auto iter = std=:find_if(ifs.begin(), ifs.end(), pred); if (iter == ifs.end()) return {}; return {*iter}; } tl=:optional<ipif&> do_stuff(ipif&); void some_func() { =/==. lookup(ip_interfaces, address_matches({192,168,1,1})) .and_then(do_stuff); =/ }
  62. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    62/74 template <typename Predicate> tl=:optional<ipif&> lookup(std=:vector<ipif>& ifs, Predicate pred) { auto iter = std=:find_if(ifs.begin(), ifs.end(), pred); if (iter == ifs.end()) return {}; return {*iter}; } void some_func() { =/==. lookup(ip_interfaces, address_matches({192,168,1,1})) .and_then(set_state(ipif=:off)); =/ }
  63. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    63/74 template <typename Predicate> tl=:optional<ipif&> lookup(std=:vector<ipif>& ifs, Predicate pred) { auto iter = std=:find_if(ifs.begin(), ifs.end(), pred); if (iter == ifs.end()) return {}; return {*iter}; } void some_func() { =/==. lookup(ip_interfaces, address_matches({192,168,1,1})) .and_then(set_state(ipif=:off)) .or_else([](){std=:cerr =< “Failed\n”;}); =/ }
  64. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    64/74 Live demo!
  65. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    65/74 ✔Very brief intro to higher order functions ✔Gradually expanding example ✔optional<T> (and extension) Higher Order Functions for Ordinary C++ Developers
  66. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    66/74 Generic library functions • equals(value) ... • compose(function...) • if_then(pred,action) • when_all(predicate...) • when_none(predicate...) • when_any(predicate...) • do_all(action...) Domain specific functions • ip_matches(ip, mask) • select_address(ipif) • select_gateway(ipif) • select_state(ipif) • set_state(ipif&) Composed domain specific functions • address_matches(ip) • state_is(state_type)
  67. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    67/74 https://github.com/rollbear/lift Generic library functions • equals(value) ... • compose(function...) • if_then(pred,action) • when_all(predicate...) • when_none(predicate...) • when_any(predicate...) • do_all(action...) Domain specific functions • ip_matches(ip, mask) • select_address(ipif) • select_gateway(ipif) • select_state(ipif) • set_state(ipif&) Composed domain specific functions • address_matches(ip) • state_is(state_type)
  68. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    68/74 https://github.com/rollbear/lift Generic library functions • equals(value) ... • compose(function...) • if_then(pred,action) • when_all(predicate...) • when_none(predicate...) • when_any(predicate...) • do_all(action...) Domain specific functions • ip_matches(ip, mask) • select_address(ipif) • select_gateway(ipif) • select_state(ipif) • set_state(ipif&) Composed domain specific functions • address_matches(ip) • state_is(state_type) As of Boost 1.67.0 (April 14th, 2018) boost::hof (higher order functions) https://www.boost.org/doc/libs/1_67_0/libs/hof/
  69. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    69/74 Take away messages • Write functions that uses auto return type to create lambdas
  70. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    70/74 Take away messages • Write functions that uses auto return type to create lambdas • Write functions that access or modify your state
  71. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    71/74 Take away messages • Write functions that uses auto return type to create lambdas • Write functions that access or modify your state • Compose functions
  72. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    72/74 Take away messages • Write functions that uses auto return type to create lambdas • Write functions that access or modify your state • Compose functions • And give names to the compositions
  73. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    73/74 Take away messages • Write functions that uses auto return type to create lambdas • Write functions that access or modify your state • Compose functions • And give names to the compositions • Functional extensions to optional<T> and expected<T,E> removes the need for many conditionals
  74. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller

    74/74 Björn Fahller https:=/github.com/rollbear/lift [email protected] @bjorn_fahller @rollbear cpplang, swedencpp Higher Order Functions for Ordinary C++ Developers