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

    View Slide

  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 (and extension)
    Higher Order Functions for Ordinary C++ Developers

    View Slide

  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.

    View Slide

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

    View Slide

  5. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller 5/74
    #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;
    }

    View Slide

  6. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller 6/74
    #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; })) {
    ==.
    }

    View Slide

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

    View Slide

  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; };
    }

    View Slide

  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 equals(int num)
    {
    return [num](int x) { return x == num; };
    }

    View Slide

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

    View Slide

  11. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller 11/74
    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; };
    }

    View Slide

  12. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller 12/74
    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

    View Slide

  13. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller 13/74
    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.

    View Slide

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

    View Slide

  15. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller 15/74
    #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)) {
    ==.
    }

    View Slide

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

    View Slide

  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 (and extension)
    Higher Order Functions for Ordinary C++ Developers

    View Slide

  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};
    };

    View Slide

  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};
    };

    View Slide

  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};
    };

    View Slide

  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};
    };

    View Slide

  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);
    };
    }

    View Slide

  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);
    };
    }

    View Slide

  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);
    };
    }

    View Slide

  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 v;
    ==.
    auto i = std=:remove_if(v.begin(), v.end(),
    ip_matches({192,168,1,1}, {255,255,0,0}));

    View Slide

  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_;
    };

    View Slide

  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_;
    };

    View Slide

  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.

    View Slide

  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))

    View Slide

  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))

    View Slide

  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
    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))

    View Slide

  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 interfaces;
    auto i = std=:find_if(interfaces.begin(), interfaces.end(),
    compose(ip_matches({192,168,1,1}),
    select_address));

    View Slide

  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 interfaces;
    auto i = std=:find_if(interfaces.begin(), interfaces.end(),
    compose(ip_matches({192,168,1,1}),
    select_address));

    View Slide

  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 interfaces;
    auto i = std=:find_if(interfaces.begin(), interfaces.end(),
    compose(ip_matches({192,168,1,1}),
    select_address);

    View Slide

  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 interfaces;
    auto i = std=:find_if(interfaces.begin(), interfaces.end(),
    address_matches({192,168,1,1}));

    View Slide

  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();
    }

    View Slide

  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)));

    View Slide

  38. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller 38/74
    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)));

    View Slide

  39. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller 39/74
    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)));

    View Slide

  40. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller 40/74
    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)));

    View Slide

  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)));

    View Slide

  42. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller 42/74
    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)));

    View Slide

  43. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller 43/74
    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)));

    View Slide

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

    View Slide

  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 (and extension)
    Higher Order Functions for Ordinary C++ Developers

    View Slide

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

    View Slide

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

    The class template std=:optional manages an optional
    contained value, i.e. a value that may or may not be present.

    View Slide

  48. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller 48/74
    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

    View Slide

  49. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller 49/74
    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

    View Slide

  50. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller 50/74
    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

    View Slide

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

    View Slide

  52. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller 52/74
    template
    std=:optional lookup(std=:vector& 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());
    }
    =/
    }

    View Slide

  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

    View Slide

  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.

    View Slide

  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
    int i = 3;
    tl=:optional v; =/ no value
    v = i; =/ v refers to i

    View Slide

  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
    int i = 3;
    tl=:optional v; =/ no value
    v = i; =/ v refers to i
    v.value() = 4; =/ i == 4

    View Slide

  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
    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

    View Slide

  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
    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};});

    View Slide

  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
    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};});

    View Slide

  60. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller 60/74
    template
    tl=:optional lookup(std=:vector& 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());
    }
    =/
    }

    View Slide

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

    View Slide

  62. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller 62/74
    template
    tl=:optional lookup(std=:vector& 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));
    =/
    }

    View Slide

  63. Higher Order Functions – NDC{Techtown} 2018 © Björn Fahller @bjorn_fahller 63/74
    template
    tl=:optional lookup(std=:vector& 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”;});
    =/
    }

    View Slide

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

    View Slide

  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 (and extension)
    Higher Order Functions for Ordinary C++ Developers

    View Slide

  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)

    View Slide

  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)

    View Slide

  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/

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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 and
    expected removes the need for many conditionals

    View Slide

  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

    View Slide