timeline.FunktionalInCpp17Cpp20Eng

Functional in C++17 and C++20

Which functional feature can we expect with C++17, and for which functional feature can we hope with C++20? This is precisely the question I will concisely answer in this post.

 

With C++17 we get fold expressions and the new container std::optional. Even more thrilling becomes C++20. Concepts, the ranges library, and improved futures support new concepts in C++.

timeline.FunktionalInCpp17Cpp20Eng

At first, to the near future. I will start in the next post with my systematic description of functional programming in C++. Therefore, I will be concise in this post. This post is only intended to make you more appetite.

C++17

Fold expressions

C++11 has Variadic Templates. These are templates that can get an arbitrary number of arguments. The arbitrary number is bound in a parameter pack. New is with C++17 that you can directly reduce a parameter pack with a binary operator. Therefore, you can directly implement Haskell’s function family foldl, foldr, foldl1, and foldr1, which reduce a list to a value.

 

Rainer D 6 P2 500x500Modernes C++ Mentoring

Be part of my mentoring programs:

  • "Fundamentals for C++ Professionals" (open)
  • "Design Patterns and Architectural Patterns with C++" (open)
  • "C++20: Get the Details" (open)
  • "Concurrency with Modern C++" (starts March 2024)
  • Do you want to stay informed: Subscribe.

     

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    // foldExpression.cpp
    
    #include <iostream>
    
    template<typename... Args>
    bool all(Args... args) { return (... && args); }
    
    template<typename... Args>
    bool any(Args... args) { return (... || args); }
    
    template<typename... Args>
    bool none(Args... args) { return not(... || args); }
    
    
    int main(){
        
      std::cout << std::endl;
    
      std::cout << std::boolalpha;
    
      std::cout << "all(true): " << all(true) << std::endl;
      std::cout << "any(true): " << any(true) << std::endl;
      std::cout << "none(true): " << none(true) << std::endl;
      
      std::cout << std::endl;
    
      std::cout << "all(true, true, true, false): " << all(true, true, true, false) << std::endl;
      std::cout << "any(true, true, true, false): " << any(true, true, true, false) << std::endl;
      std::cout << "none(true, true, true, false): " << none(true, true, true, false) << std::endl;
      
      std::cout << std::endl;
      
      std::cout << "all(false, false, false, false): " << all(false, false, false, false) << std::endl;
      std::cout << "any(false, false, false, false): " << any(false, false, false, false) << std::endl;
      std::cout << "none(false, false, false, false): " << none(false, false, false, false) << std::endl;
      
      std::cout << std::endl;
      
    }
    

     

    The function templates all, any, and none return at compile-time true, or false. I will have a closer look at the function template any in lines 5 and 6. The parameter pack (…) is unpacked on the binary operator (… && args). The three dots define (ellipse) the parameter pack.

    For the program’s output, I use the online compiler on cppreference.com.

    foldExpressions

    Haskell has the maybe monad, and C++17 will get std::optional.

    std::optional

    std::optional stands for a calculation that maybe have a value. A find algorithm or a query of a hash table must deal with the fact that no value is available. Often, you use special values to indicate that you get no result. In short, a non-results. Often null pointers, empty strings, or special integer values are used for non-results. This is inconvenient and error-prone because you have to deal especially with non-result, and you have to distinguish the non-result from a regular result. In case of a non-result, you get with std::optional no value. 

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    // optional.cpp
    
    #include <experimental/optional>
    #include <iostream>
    #include <vector>
    
    std::experimental::optional<int> getFirst(const std::vector<int>& vec){
      if ( !vec.empty() ) return std::experimental::optional<int>(vec[0]);
      else return std::experimental::optional<int>();
    }
    
    int main(){
        
        std::vector<int> myVec{1,2,3};
        std::vector<int> myEmptyVec;
        
        auto myInt= getFirst(myVec);
        
        if (myInt){
            std::cout << "*myInt: "  << *myInt << std::endl;
            std::cout << "myInt.value(): " << myInt.value() << std::endl;
            std::cout << "myInt.value_or(2017):" << myInt.value_or(2017) << std::endl;
        }
        
        std::cout << std::endl;
        
        auto myEmptyInt= getFirst(myEmptyVec);
        
        if (!myEmptyInt){
            std::cout << "myEmptyInt.value_or(2017):" << myEmptyInt.value_or(2017) << std::endl;
        }
       
    }
    

     

    std::optional is currently in the namespace experimental. That will change with C++17. If it exists, the function getFirst will return the first element (line 8). If not, a std::optional<int> object. I use in the main function two vectors. The calls getFirst in lines 17 and 27 return a std::optional object. In the case of myInt (line 19), the object has a value; in the case of myEmptyInt (line 29), no value. Now, I can display the value of myInt (lines 20 – 22). The method value_or in lines 22 and 30 will return a value if std::optional-object has a value if not a default value.

    optinal

    The impact of functional programming in C++ – particularly Haskell – increases significantly with C++20. Of course, it’s a little bit risky to predict C++20. I made a mistake once and said that the following features are part of C++17, which is, of course, not true.

    C++20

    Promised, the details of concepts, the ranges library, and the improved futures will follow in future posts.

    Concepts

    Type classes in Haskell are interfaces for similar types. If a type is a member of a type class, it will have specific properties. Type classes play in generic programming a similar role as interfaces in object-oriented programming. Inspired by type classes, you can specify requirements for the template parameters. The new functionality has the name concepts. For example, the sort algorithm requires that a template argument be sorted.

    template<typename Cont>
      requires Sortable<Cont>()
    void sort(Cont& container){...}
    

     

    What are the benefits of concepts? At first, the template declaration states which properties must hold for the template arguments. Therefore, the compiler can detect the break of the contract and display an unambiguous error message.

    std::list<int> lst = {1998,2014,2003,2011};
    sort(lst); // ERROR: lst is no random-access container with <
    

     

    The C++ community waits at least as eagerly for concepts as for the new ranges library from Eric Niebler.

    Ranges library

    From the birds-eye perspective, the ranges library empowers you to apply the Standard Template Library algorithms directly on the whole container. But under the hood, we get new programming techniques.

    • Lazy evaluation that enables you to apply the algorithm on infinite data streams.
    • Thanks to the pipe symbol, we get function composition.
    • Thanks to Range comprehension, you can directly create ranges similar to list comprehension in Python or Haskell.
    1
    2
    3
    4
      auto odds= view::transform([](int i){ return i*i; }) |
                 view::remove_if([](int i){ return i % 2 == 0; }) |
                 view::take_while([](int i){ return i < 1000; });
      auto oddNumbers= view::ints(1) | odds;
    

     

    oddNumbers holds, as a result, the square of all odd numbers smaller than 1000: 1, 9, 25, …, 841, 961. How does it work? The function composition calculates at first to each number is square (line 1), removes all even numbers (line 2), and stops if the square of numbers is greater than 1000 (line 3). I use odds in line number 4. view::int(1) creates the infinite input stream of integers starting with 0. Odds will stop the input stream.

    There is proposal n3721 for the improvement of futures. The main issue with C++11 futures is that you can not compose them. C++20 cleans it up.

    Improved futures

    The code snippet gives you an idea how the future of std::future will look like.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    future<int> f1= async([]() {return 123;});
    future<string> f2 = f1.then([](future<int> f){ return f.get().to_string(); });
    
    future<int> futures[] = {async([]() { return intResult(125); }), 
                             async([]() { return intResult(456); })};
    future<vector<future<int>>> any_f = when_any(begin(futures), end(futures));
    
    future<int> futures[] = {async([]() { return intResult(125); }), 
                             async([]() { return intResult(456); })};
    future<vector<future<int>>> all_f = when_all(begin(futures), end(futures));
    

     

    f1.then in line 2 returns a new future that will be executed if f1 is done with its work. any_f (line 6) will be performed if one of the futures in lines 4 and 5 is done. all_f will be performed if all of the futures in lines 8 and 9 are done.

    One question is still not answered in my post. What have futures with functional programming in common? A lot! The improved futures are a monad. Suppose you don’t believe me. Watch: I see a Monad in your Future (Bartosz Milewski). 

    What’s next?

    Now, it’s time to start with my systematic. In the next post, I will answer the question: What is functional programming?

     

     

     

     

     

     

    Thanks a lot to my Patreon Supporters: Matt Braun, Roman Postanciuc, Tobias Zindl, G Prvulovic, Reinhold Dröge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Jozo Leko, John Breland, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Kris Kafka, Mario Luoni, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Daniel Hufschläger, Alessandro Pezzato, Bob Perry, Satish Vangipuram, Andi Ireland, Richard Ohnemus, Michael Dunsky, Leo Goodstadt, John Wiederhirn, Yacob Cohen-Arazi, Florian Tischler, Robin Furness, Michael Young, Holger Detering, Bernd Mühlhaus, Stephen Kelley, Kyle Dean, Tusar Palauri, Dmitry Farberov, Juan Dent, George Liao, Daniel Ceperley, Jon T Hess, Stephen Totten, Wolfgang Fütterer, Matthias Grün, Phillip Diekmann, Ben Atakora, Ann Shatoff, Rob North, Bhavith C Achar, Marco Parri Empoli, moon, Philipp Lenk, Hobsbawm, and Charles-Jianye Chen.

    Thanks, in particular, to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, John Nebel, Mipko, Alicja Kaminska, Slavko Radman, and David Poole.

    My special thanks to Embarcadero
    My special thanks to PVS-Studio
    My special thanks to Tipi.build 
    My special thanks to Take Up Code
    My special thanks to SHAVEDYAKS

    Seminars

    I’m happy to give online seminars or face-to-face seminars worldwide. Please call me if you have any questions.

    Standard Seminars (English/German)

    Here is a compilation of my standard seminars. These seminars are only meant to give you a first orientation.

    • C++ – The Core Language
    • C++ – The Standard Library
    • C++ – Compact
    • C++11 and C++14
    • Concurrency with Modern C++
    • Design Pattern and Architectural Pattern with C++
    • Embedded Programming with Modern C++
    • Generic Programming (Templates) with C++
    • Clean Code with Modern C++
    • C++20

    Online Seminars (German)

    Contact Me

    Modernes C++ Mentoring,

     

     

    0 replies

    Leave a Reply

    Want to join the discussion?
    Feel free to contribute!

    Leave a Reply

    Your email address will not be published. Required fields are marked *