Skip to main content

Posts

Folding Functions

In the last post we looked at basic usage of C++17 Fold Expressions. I found that many posts on this topic discuss simple types and ignore how folds may be applicable to more complex types as well. [Edit: Please see the comments section for some examples elsewhere in the blogosphere.] In this post I'm going to describe folding over functions. Composing Functions Function composition is a powerful way of creating complex functions from simple ones. Functions that accept a single argument and return a value are easily composable. Consider the following example to compose two std::functions. template <class A, class B, class C> std::function<C(A)> compose(std::function<B(A)> f, std::function<C(B)> g) { return [=](A a) -> C { return g(f(a)); }; } int main(void) { std::function<int(std::string)> to_num = [](std::string s) { return atoi(s.c_str()); }; std::function<bool(int)> is_even = [](int i) { return i%2==0; }; auto is_str_e...

Understanding Fold Expressions

C++17 has an interesting new feature called fold expressions . Fold expressions offer a compact syntax to apply a binary operation to the elements of a parameter pack. Here’s an example. template <typename... Args> auto addall(Args... args) { return (... + args); } addall(1,2,3,4,5); // returns 15. This particular example is a unary left fold . It's equivalent to ((((1+2)+3)+4)+5). It reduces/folds the parameter pack of integers into a single integer by applying the binary operator successively. It's unary because it does not explicitly specify an init (a.k.a. identity) argument. So, let add it. template <typename... Args> auto addall(Args... args) { return (0 + ... + args); } addall(1,2,3,4,5); // returns 15. This version of addall is a binary left fold . The init argument is 0 and it's redundant (in this case). That's because this fold expression is equivalent to (((((0+1)+2)+3)+4)+5). Explicit identity elements will come in handy a little ...

Dependently-typed Curried printf in C++

Just a few days ago I came across an intriguing blog-post  about type-safe printf using dependent typing. The blog-post has since become inaccessible and therefore, I've copied an excerpt here. I want to thank Zesen Qian for publishing this blog-post. .... printf  originated from the C programming language and has been a headache since then because a proper call of  printf  requires the number and types of arguments to match the format string; otherwise, it may visit a wild memory or a wrong register. In recent versions of GCC this issue is addressed by type checks hard coded into the compiler itself, which is ugly because the compiler should not be caring about the safety of applications of a specific function.... The key issue here is that, considering the curried version, the type of the returned function of applying the format string to  printf , actually depends on the value of that format string. That is to say,  printf "%s" : String -> Str...

Covariance and Contravariance in C++ Standard Library

Covariance and Contravariance are concepts that come up often as you go deeper into generic programming. While designing a language that supports parametric polymorphism (e.g., templates in C++, generics in Java, C#), the language designer has a choice between Invariance, Covariance, and Contravariance when dealing with generic types. C++'s choice is "invariance". Let's look at an example. struct Vehicle {}; struct Car : Vehicle {}; std::vector<Vehicle *> vehicles; std::vector<Car *> cars; vehicles = cars; // Does not compile The above program does not compile because C++ templates are invariant. Of course, each time a C++ template is instantiated, the compiler creates a brand new type that uniquely represents that instantiation. Any other type to the same template creates another unique type that has nothing to do with the earlier one. Any two unrelated user-defined types in C++ can't be assigned to each-other by default. You have to provide a...

CppCon'15 and Silicon Valley Code Camp Presentations

In last couple of months I did a couple of presentations about my recent projects in C++. Session videos, slides, and code for all the presentations are now available online. Both projects have functional programming at their heart. I've found exploring functional programming in modern C++ quite a fun ride. Without further ado, here's the content CppCon'15: Reactive Stream Processing in Industrial IoT using DDS and RxCpp Topic: 50 billion devices will be connected to the Internet by 2020. Many of them will belong to national critical infrastructure (smart power grids, smart roads, smart hospitals, smart cities) – forming the Industrial Internet of Things (IIoT). These devices will generate data streams that will need to be correlated, merged, filtered, and analyzed in real-time at the edge. This talk will explore an elegant solution to this problem that is productive, composable, concurrency-friendly, and scales well. We utilize OMG’s Data Distribution Service f...

Fun with Lambdas: C++14 Style (part 4)

This is part 4 in the series of Fun with Lambdas: C++14 Style . The previous posts are part 3 , part 2 , and part 1 . C++14 has a number of features that support functional-style design. By "functional-style" I mean heavy use of higher-order functions (functions that take other functions as arguments). Quite often arguments to the higher-order functions are lambdas (closures, to be precise). With automatic return type deduction for normal functions, writing higher-order function becomes very easy and seamless in C++14. This time, I have chosen a "text-book" example to show you the power of C++14: Composable Data Generators What is a Generator? A Generator<T> produces values of type T randomly. There is already a random number generator defined in the C library: random() . It produces long ints. We can use this basic generator to create higher-level generators, such as bool, character, floating point numbers, etc. Even random sequence and structure g...

Fun with C++14 Lambdas at Silicon Valley Code Camp

Believe it or not, but the 9th Silicon Valley Code Camp is less than 2 weeks away and I can't wait to be at the largest software technology conference setup by developers for developers---and here is the best part---at no cost to the attendees. So far, there are 234 registered sessions, 7 technical tracks , and over 3100 registrations. So mark your calendar--it's October 11th and 12th, Saturday and Sunday, as always. C++ is hot again at SVCC and third year in a row there is a dedicated track for modern C++. There are 11 sessions  covering a wide variety of topics related to modern C++ programming. I wanna thank SVCC organizers who generously allowed me to present two sessions: The first one is titled: Fun with Lambdas: C++14 Style [ video ]. You may be following the Fun with Lambdas series on this blog and hopefully having some fun too! I'll present a sampling of the content discussed here with new insights. Check out  part 1 , part 2 , and part 3 if you haven...

Short-circuiting overloaded && and || using expression templates

This blog post is just a quick note that C++ offers (at least) two distinct ways to represent lazy computation that is lexically in the same scope but may execute lazily at a later time. In doing so, the computation must capture the local context (i.e., variables) so that it can be used later when needed. Clearly, lambda expressions are a direct language supported mechanism for that. Closures that come out of a lambda expression often capture the context and of course some behavior to be run later. The second mechanism is about 20 years old (as of this writing): Expression Templates . Lets take an example of short-circuiting overloaded && and || operators. Regular overloaded && and || do not short circuit in C++. The reason is that before calling the overloaded operator &&, both the left-hand-side and the right-hand-side arguments of the overloaded function are evaluated. A function call is a sequence-point and therefore all the computations and the side-ef...

Fun with Lambdas: C++14 Style (part 3)

Now that we have C++14 , it has opened up doors for truly mind-bending uses of lambdas--more specifically--generic lambdas. This blog post is the third installment in the series of "Fun with Lambdas: C++14 Style". Check out part 1 and part 2 if you have not already. This post is about "monadic tuples". Monad--a simple but powerful abstraction, however, considered quite difficult to understand in the imperative circles. We will look into what's know as the "continuation monad". As it turns out, in C++14, you need just a couple of lines of code to create an instance of a continuation monad. I'm fairly new to the world of monads. So, things did not begin with great clarity for me. It all started with an intriguing question on Stackoverflow . As it turns out the same "trick" is also used in Boost.Hana and discussed on boost mailing list here . What you see below is more or less how I came to understand the idiom as an instance ...