Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 2/93 Very brief intro to higher order functions Gradually expanding example optional (and extension) Managing overload sets Higher Order Functions for Ordinary C++ Developers

Slide 3

Slide 3 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 3/93 Definition A higher-order function is a function that takes other functions as arguments or returns a function as result.

Slide 4

Slide 4 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 4/93 #include #include std=:vector v; ==. if (std=:none_of(std=:begin(v), std=:end(v), [](int x) { return x == 0; })) { ==. }

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 6/93 #include #include std=:vector 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; })) { ==. }

Slide 7

Slide 7 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 7/93 [num](int x){ return x == num; }

Slide 8

Slide 8 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 8/93 auto equals(int num) { return [num](int x){ return x == num; }; }

Slide 9

Slide 9 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 9/93 auto equals(int num) { return [num](int x){ return x == num; }; } std=:function equals(int num) { return [num](int x) { return x == num; }; }

Slide 10

Slide 10 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 10/93 template auto equals(T key) { return [key](auto const& x){ return x == key; }; }

Slide 11

Slide 11 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 11/93 template auto equals(T key) { return [key](auto const& x){ return x == key; }; } template std=:function equals(T key) { return [key](T x) { return x == key; }; }

Slide 12

Slide 12 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 12/93 template auto equals(T key) { return [key](auto const& x){ return x == key; }; } template std=:function equals(T key) { return [key](T x) { return x == key; }; } Callable with anything equality comparable with T, for example C-string and std=:string

Slide 13

Slide 13 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 13/93 template auto equals(T key) { return [key](auto const& x){ return x == key; }; } template std=:function 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.

Slide 14

Slide 14 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 14/93 template auto equals(T key) { return [key](auto const& x){ return x == key; }; }

Slide 15

Slide 15 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 15/93 #include #include std=:vector 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)) { ==. }

Slide 16

Slide 16 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 16/93 Live demo!

Slide 17

Slide 17 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 17/93 ✔Very brief intro to higher order functions Gradually expanding example optional (and extension) Managing overload sets Higher Order Functions for Ordinary C++ Developers

Slide 18

Slide 18 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 18/93 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}; };

Slide 19

Slide 19 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 19/93 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}; };

Slide 20

Slide 20 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 20/93 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}; };

Slide 21

Slide 21 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 21/93 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}; };

Slide 22

Slide 22 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 22/93 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); }; }

Slide 23

Slide 23 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 23/93 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); }; }

Slide 24

Slide 24 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 24/93 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); }; }

Slide 25

Slide 25 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 25/93 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 v; ==. auto i = std=:remove_if(v.begin(), v.end(), ip_matches({192,168,1,1}, {255,255,0,0}));

Slide 26

Slide 26 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 26/93 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_; };

Slide 27

Slide 27 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 27/93 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_; };

Slide 28

Slide 28 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 28/93 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.

Slide 29

Slide 29 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 29/93 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))

Slide 30

Slide 30 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 30/93 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))

Slide 31

Slide 31 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 31/93 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 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))

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 33/93 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 interfaces; auto i = std=:find_if(interfaces.begin(), interfaces.end(), compose(ip_matches({192,168,1,1}), select_address));

Slide 34

Slide 34 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 34/93 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 interfaces; auto i = std=:find_if(interfaces.begin(), interfaces.end(), compose(ip_matches({192,168,1,1}), select_address);

Slide 35

Slide 35 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 35/93 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 interfaces; auto i = std=:find_if(interfaces.begin(), interfaces.end(), address_matches({192,168,1,1}));

Slide 36

Slide 36 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 36/93 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(); }

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 38/93 template 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)));

Slide 39

Slide 39 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 39/93 template 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)));

Slide 40

Slide 40 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 40/93 template 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)));

Slide 41

Slide 41 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 41/93 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)));

Slide 42

Slide 42 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 42/93 template auto if_then(Predicate predicate, Action action) { return [=](auto=& x) { if (predicate(x)) { action(std=:forward(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)));

Slide 43

Slide 43 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 43/93 template auto if_then(Predicate predicate, Action action) { return [=](auto=& x) { if (predicate(x)) { action(std=:forward(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)));

Slide 44

Slide 44 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 44/93 Live demo!

Slide 45

Slide 45 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 45/93 ✔Very brief intro to higher order functions ✔Gradually expanding example optional (and extension) Managing overload sets Higher Order Functions for Ordinary C++ Developers

Slide 46

Slide 46 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 46/93 std=:optional

Slide 47

Slide 47 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 47/93 std=:optional ● The class template std=:optional manages an optional contained value, i.e. a value that may or may not be present.

Slide 48

Slide 48 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 48/93 std=:optional ● 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

Slide 49

Slide 49 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 49/93 std=:optional ● 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

Slide 50

Slide 50 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 50/93 std=:optional ● 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

Slide 51

Slide 51 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 51/93 template std=:optional lookup(std=:vector& ifs, Predicate pred) { auto iter = std=:find_if(ifs.begin(), ifs.end(), pred); if (iter == ifs.end()) return std=:nullopt; return {*iter}; }

Slide 52

Slide 52 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 52/93 template std=:optional lookup(std=:vector& ifs, Predicate pred) { auto iter = std=:find_if(ifs.begin(), ifs.end(), pred); if (iter == ifs.end()) return std=:nullopt; 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()); } =/ }

Slide 53

Slide 53 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 53/93 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

Slide 54

Slide 54 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 54/93 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 P0798R2: Monadic operations for std::optional.

Slide 55

Slide 55 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 55/93 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 int i = 3; tl=:optional v; =/ no value v = i; =/ v refers to i

Slide 56

Slide 56 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 56/93 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 int i = 3; tl=:optional v; =/ no value v = i; =/ v refers to i v.value() = 4; =/ i == 4

Slide 57

Slide 57 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 57/93 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 int i = 3; tl=:optional 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

Slide 58

Slide 58 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 58/93 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 int i = 3; tl=:optional 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{i};});

Slide 59

Slide 59 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 59/93 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 int i = 3; tl=:optional 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{i};});

Slide 60

Slide 60 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 60/93 template tl=:optional lookup(std=:vector& ifs, Predicate pred) { auto iter = std=:find_if(ifs.begin(), ifs.end(), pred); if (iter == ifs.end()) return tl=:nullopt; 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()); } =/ }

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 63/93 template tl=:optional lookup(std=:vector& ifs, Predicate pred) { auto iter = std=:find_if(ifs.begin(), ifs.end(), pred); if (iter == ifs.end()) return tl=:nullopt; 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”;}); =/ }

Slide 64

Slide 64 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 64/93 Live demo!

Slide 65

Slide 65 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 65/93 ✔Very brief intro to higher order functions ✔Gradually expanding example ✔optional (and extension) Managing overload sets Higher Order Functions for Ordinary C++ Developers

Slide 66

Slide 66 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 66/93 class ipif { public: ==. ip_address addr() const { return addr_;} }; ip_address select_addr(ipif const& interface) { return interface.addr(); }

Slide 67

Slide 67 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 67/93 class ipif { public: ==. ip_address addr() const { return addr_;} }; ip_address select_addr(ipif const& interface) { return interface.addr(); } std=:vector addresses(std=:vector& const v) { std=:vector rv; std=:transform(std=:begin(v), std=:end(v), std=:back_inserter(rv), select_addr); return rv; }

Slide 68

Slide 68 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 68/93 class ipif { public: ==. ip_address addr() const { return addr_;} }; ip_address select_addr(ipif const& interface) { return interface.addr(); } class street_address; class customer { ==. street_address addr() const { return addr_; } }; street_address select_addr(customer const& c) { return c.addr(); } std=:vector addresses(std=:vector& const v) { std=:vector rv; std=:transform(std=:begin(v), std=:end(v), std=:back_inserter(rv), select_addr); return rv; }

Slide 69

Slide 69 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 69/93 class ipif { public: ==. ip_address addr() const { return addr_;} }; ip_address select_addr(ipif const& interface) { return interface.addr(); } class street_address; class customer { ==. street_address addr() const { return addr_; } }; street_address select_addr(customer const& c) { return c.addr(); } std=:vector addresses(std=:vector& const v) { std=:vector rv; std=:transform(std=:begin(v), std=:end(v), std=:back_inserter(rv), select_addr); return rv; } example.cpp (40): error C2672: 'std=:transform': no matching overloaded function found (40): error C2783: '_OutIt std=:transform(_InIt,_InIt,_OutIt,_Fn1)': could not deduce template argument for '_Fn1'

Slide 70

Slide 70 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 70/93 class ipif { public: ==. ip_address addr() const { return addr_;} }; ip_address select_addr(ipif const& interface) { return interface.addr(); } class street_address; class customer { ==. street_address addr() const { return addr_; } }; street_address select_addr(customer const& c) { return c.addr(); } std=:vector addresses(std=:vector& const v) { std=:vector rv; std=:transform(std=:begin(v), std=:end(v), std=:back_inserter(rv), select_addr); return rv; } :38:5: error: no matching function for call to 'transform' std=:transform(std=:begin(v), std=:end(v), ^~~~~~~~~~~~~~ ==./include/c=+/7.2.0/bits/stl_algo.h:4295:5: note: candidate template ignored: couldn't infer template argument '_UnaryOperation' transform(_InputIterator =_first, _InputIterator =_last, ^ ==./include/c=+/7.2.0/bits/stl_algo.h:4332:5: note: candidate function template not viable: requires 5 arguments, but 4 were provided transform(_InputIterator1 =_first1, _InputIterator1 =_last1, ^

Slide 71

Slide 71 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 71/93 class ipif { public: ==. ip_address addr() const { return addr_;} }; ip_address select_addr(ipif const& interface) { return interface.addr(); } class street_address; class customer { ==. street_address addr() const { return addr_; } }; street_address select_addr(customer const& c) { return c.addr(); } std=:vector addresses(std=:vector const& v) { std=:vector rv; std=:transform(std=:begin(v), std=:end(v), std=:back_inserter(rv), select_addr); return rv; }

Slide 72

Slide 72 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 72/93 class ipif { public: ==. ip_address addr() const { return addr_;} }; ip_address select_addr(ipif const& interface) { return interface.addr(); } class street_address; class customer { ==. street_address addr() const { return addr_; } }; street_address select_addr(customer const& c) { return c.addr(); } std=:vector addresses(std=:vector const& v) { std=:vector rv; std=:transform(std=:begin(v), std=:end(v), std=:back_inserter(rv), select_addr); return rv; } How to solve this?

Slide 73

Slide 73 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 73/93 class ipif { public: ==. ip_address addr() const { return addr_;} }; ip_address select_addr(ipif const& interface) { return interface.addr(); } class street_address; class customer { ==. street_address addr() const { return addr_; } }; street_address select_addr(customer const& c) { return c.addr(); } std=:vector addresses(std=:vector const& v) { std=:vector rv; std=:transform(std=:begin(v), std=:end(v), std=:back_inserter(rv), select_addr); return rv; } Solution #1

Slide 74

Slide 74 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 74/93 class ipif { public: ==. ip_address addr() const { return addr_;} }; ip_address select_addr(ipif const& interface) { return interface.addr(); } class street_address; class customer { ==. street_address addr() const { return addr_; } }; street_address select_addr(customer const& c) { return c.addr(); } std=:vector addresses(std=:vector const& v) { std=:vector rv; std=:transform(std=:begin(v), std=:end(v), std=:back_inserter(rv), select_addr); return rv; } ¯\_( ツ )_/¯

Slide 75

Slide 75 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 75/93 class ipif { public: ==. ip_address addr() const { return addr_;} }; ip_address select_addr(ipif const& interface) { return interface.addr(); } class street_address; class customer { ==. street_address addr() const { return addr_; } }; street_address select_addr(customer const& c) { return c.addr(); } std=:vector addresses(std=:vector const& v) { std=:vector rv; std=:transform(std=:begin(v), std=:end(v), std=:back_inserter(rv), select_addr); return rv; } ¯\_( ツ )_/¯ ● This is rarely a problem, so why worry? ● Arrange your code such that only one version is needed in the same source file.

Slide 76

Slide 76 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 76/93 class ipif { public: ==. ip_address addr() const { return addr_;} }; ip_address select_addr(ipif const& interface) { return interface.addr(); } class street_address; class customer { ==. street_address addr() const { return addr_; } }; street_address select_addr(customer const& c) { return c.addr(); } std=:vector addresses(std=:vector const& v) { std=:vector rv; std=:transform(std=:begin(v), std=:end(v), std=:back_inserter(rv), select_addr); return rv; } Solution #2

Slide 77

Slide 77 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 77/93 class ipif { public: ==. ip_address addr() const { return addr_;} }; ip_address select_addr(ipif const& interface) { return interface.addr(); } class street_address; class customer { ==. street_address addr() const { return addr_; } }; street_address select_addr(customer const& c) { return c.addr(); } std=:vector addresses(std=:vector const& v) { std=:vector rv; std=:transform(std=:begin(v), std=:end(v), std=:back_inserter(rv), [](auto const& p) { return select_addr(p); }); return rv; } ● Call through a generic lambda for the access

Slide 78

Slide 78 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 78/93 class ipif { public: ==. ip_address addr() const { return addr_;} }; ip_address select_addr(ipif const& interface) { return interface.addr(); } class street_address; class customer { ==. street_address addr() const { return addr_; } }; street_address select_addr(customer const& c) { return c.addr(); } std=:vector addresses(std=:vector const& v) { std=:vector rv; std=:transform(std=:begin(v), std=:end(v), std=:back_inserter(rv), [](auto const& p) { return select_addr(p); }); return rv; } ● Call through a generic lambda for the access + OK to write and use occasionally - Becomes cumbersome if needed frequently

Slide 79

Slide 79 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 79/93 class ipif { public: ==. ip_address addr() const { return addr_;} }; ip_address select_addr(ipif const& interface) { return interface.addr(); } class street_address; class customer { ==. street_address addr() const { return addr_; } }; street_address select_addr(customer const& c) { return c.addr(); } std=:vector addresses(std=:vector const& v) { std=:vector rv; std=:transform(std=:begin(v), std=:end(v), std=:back_inserter(rv), select_addr); return rv; } Solution #2b

Slide 80

Slide 80 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 80/93 class ipif { public: ==. ip_address addr() const { return addr_;} }; ip_address select_addr(ipif const& interface) { return interface.addr(); } class street_address; class customer { ==. street_address addr() const { return addr_; } }; street_address select_addr(customer const& c) { return c.addr(); } std=:vector addresses(std=:vector const& v) { std=:vector rv; std=:transform(std=:begin(v), std=:end(v), std=:back_inserter(rv), LIFT(select_addr)); return rv; } ● Macro for a generic lambda for the access #define LIFT(func) \ [](auto=& ==. p) \ { \ return func(std=:forward(p)==.)); \ }

Slide 81

Slide 81 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 81/93 class ipif { public: ==. ip_address addr() const { return addr_;} }; ip_address select_addr(ipif const& interface) { return interface.addr(); } class street_address; class customer { ==. street_address addr() const { return addr_; } }; street_address select_addr(customer const& c) { return c.addr(); } std=:vector addresses(std=:vector const& v) { std=:vector rv; std=:transform(std=:begin(v), std=:end(v), std=:back_inserter(rv), LIFT(select_addr)); return rv; } ● Macro for a generic lambda for the access #define LIFT(func) \ [](auto=& ==. p) \ { \ return func(std=:forward(p)==.)); \ } + Fairly easy to use - Macros are evil

Slide 82

Slide 82 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 82/93 Live demo!

Slide 83

Slide 83 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 83/93 ✔Very brief intro to higher order functions ✔Gradually expanding example ✔optional (and extension) ✔Managing overload sets Higher Order Functions for Ordinary C++ Developers

Slide 84

Slide 84 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 84/93 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) Generic library functions ● equals(value) ... ● compose(function...) ● if_then(pred,action) ● when_all(predicate...) ● when_none(predicate...) ● when_any(predicate...) ● do_all(action...) ● LIFT(overload_set)

Slide 85

Slide 85 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 85/93 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...) ● LIFT(overload_set) 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)

Slide 86

Slide 86 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 86/93 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...) ● LIFT(overload_set) 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_68_0/libs/hof/

Slide 87

Slide 87 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 87/93 Take away messages ● Write functions that uses auto return type to create lambdas

Slide 88

Slide 88 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 88/93 Take away messages ● Write functions that uses auto return type to create lambdas ● Write functions that access or modify your state

Slide 89

Slide 89 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 89/93 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

Slide 90

Slide 90 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 90/93 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 and expected removes the need for many conditionals

Slide 91

Slide 91 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 91/93 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 and expected removes the need for many conditionals ● Overloads can be a bit of a bother.

Slide 92

Slide 92 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 92/93 Resources Pacific++ 2018: Toby Allsopp “Surfacing Composition” www.youtube.com/watch?v=_x1EvX-q3QU CppCon 2018: Simon Brand “Overloading: The Bane of All Higher-Order Functions” www.youtube.com/watch?v=L_QKlAx31Pw https://www.boost.org/doc/libs/1_68_0/libs/hof/ https://github.com/rollbear/lift Functional Programming in C++ Ivan Čukić ISBN 1617293814

Slide 93

Slide 93 text

Higher Order Functions – Meeting C++ 2018 © Björn Fahller @bjorn_fahller 93/93 Björn Fahller Higher Order Functions for Ordinary C++ Developers [email protected] @bjorn_fahller @rollbear