Saturday, September 20, 2014

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-effects are complete before making the function call. This is eager strategy.

Expression Templates is a library-only approach to defer computation at a later time while keeping the context of the original expression around. Sounds a lot like lambda expressions.

Consider the struct S below, which is convertible to bool. I would like to implement short-circuiting && and || for this type.

struct S
{
  bool val;
  explicit S(bool b) : val(b) {}

  explicit operator bool () const 
  {
    return val;
  }
};

S operator && (const S & s1, const S & s2)
{
  return s1? S{s1.val && s2.val} : s1;
}

int main(void)
{
  S s1{false}, s2{true}, s3{true};
  S s4 = s1 && s2 && s3; // false
}
There is hardly any optimization at all. The overloaded && operator is called twice no matter what. Although the result of the expression s1 && s2 && s3 is known just by looking at s1. An opportunity for optimization is wasted (if you ever wanted to optimize that way!).

So let's use expression templates. The trick is to convert the expression into a tree of recursively nested instantiations of the Expr template. The tree is evaluated separately after construction.

The following code implements short-circuited && and || operators for S as long as it provides logical_and and logical_or free functions and it is convertible to bool. The code is in C++14 but the idea is applicable in C++98 also.

#include <iostream>

struct S
{
  bool val;

  explicit S(int i) : val(i) {}  
  explicit S(bool b) : val(b) {}

  template <class Expr>
  S (const Expr & expr)
   : val(evaluate(expr).val)
  { }

  template <class Expr>
  S & operator = (const Expr & expr)
  {
    val = evaluate(expr).val;
    return *this;
  }

  explicit operator bool () const 
  {
    return val;
  }
};

S logical_and (const S & lhs, const S & rhs)
{
    std::cout << "&& ";
    return S{lhs.val && rhs.val};
}

S logical_or (const S & lhs, const S & rhs)
{
    std::cout << "|| ";
    return S{lhs.val || rhs.val};
}


const S & evaluate(const S &s) 
{
  return s;
}

template <class Expr>
S evaluate(const Expr & expr) 
{
  return expr.eval();
}

struct LazyAnd 
{
  template <class LExpr, class RExpr>
  auto operator ()(const LExpr & l, const RExpr & r) const
  {
    const auto & temp = evaluate(l);
    return temp? logical_and(temp, evaluate(r)) : temp;
  }
};

struct LazyOr 
{
  template <class LExpr, class RExpr>
  auto operator ()(const LExpr & l, const RExpr & r) const
  {
    const auto & temp = evaluate(l);
    return temp? temp : logical_or(temp, evaluate(r));
  }
};


template <class Op, class LExpr, class RExpr>
struct Expr
{
  Op op;
  const LExpr &lhs;
  const RExpr &rhs;

  Expr(const LExpr& l, const RExpr & r)
   : lhs(l),
     rhs(r)
  {}

  auto eval() const 
  {
    return op(lhs, rhs);
  }
};

template <class LExpr>
auto operator && (const LExpr & lhs, const S & rhs)
{
  return Expr<LazyAnd, LExpr, S> (lhs, rhs);
}

template <class LExpr, class Op, class L, class R>
auto operator && (const LExpr & lhs, const Expr<Op,L,R> & rhs)
{
  return Expr<LazyAnd, LExpr, Expr<Op,L,R>> (lhs, rhs);
}

template <class LExpr>
auto operator || (const LExpr & lhs, const S & rhs)
{
  return Expr<LazyOr, LExpr, S> (lhs, rhs);
}

template <class LExpr, class Op, class L, class R>
auto operator || (const LExpr & lhs, const Expr<Op,L,R> & rhs)
{
  return Expr<LazyOr, LExpr, Expr<Op,L,R>> (lhs, rhs);
}

std::ostream & operator << (std::ostream & o, const S & s)
{
  o << s.val;
  return o;
}

S and_result(S s1, S s2, S s3)
{
  return s1 && s2 && s3;
}

S or_result(S s1, S s2, S s3)
{
  return s1 || s2 || s3;
}

int main(void) 
{
  for(int i=0; i<= 1; ++i)
    for(int j=0; j<= 1; ++j)
      for(int k=0; k<= 1; ++k)
        std::cout << i << j << k << " " << and_result(S{i}, S{j}, S{k}) << std::endl;

  for(int i=0; i<= 1; ++i)
    for(int j=0; j<= 1; ++j)
      for(int k=0; k<= 1; ++k)
        std::cout << i << j << k << " " << or_result(S{i}, S{j}, S{k}) << std::endl;

  return 0;
}
Let's break it apart piece by piece.

Type S has new conversion and assignment operators that convert a generic Expr argument that is convertible to S. The expression is not evaluated until it is actually assigned to another S. We just call evaluate on the expression to begin execution of the computation wrapped inside Expr. logical_and and logical_or are free functions that perform the non-short-circuiting logical operations because we're going to hijack the overloaded && and || for short-circuiting.

The evaluate free functions take care of the trivial base case when Expr happens to just another S and all other cases when Expr is a compound expression.

struct LazyAnd and LazyOr are the short-circuiting && and ||. They always evaluate the left-hand-side but may not evaluate the right-hand-side if it is not required.

Expr template enables construction of so called expression templates. It is meant to be instantiated recursively. for example, an expression template for (s1 && s2) looks like Expr<LazyAnd, S, S> whereas for (s1 && s2 && s3) it is Expr<LazyAnd, Expr<LazyAnd, S , S>, S>. One last example: (s1 && (s2 && s3)) becomes Expr<LazyAnd, S, Expr<LazyAnd, S , S>>.

Of course, creating the nested Expr instantiations manually is berserk. So we use overloaded && and || operators that instead of computing the result eagerly, produce and expression that we can evaluate later. I've avoided writing overly generic && and || operator by using the second argument that is either S or and Expr. So the operator does not match with types outside those. Take a look at the examples above. It is fairly straightforward to see how an expressions turns into a tree. Note that construction of tree does not involve calling logical_and and logical_or functions

Finally, the assignment operator and copy-ctor of S take care of executing the expression. LazyAnd and LazyOr do the least possible work while ensuring that left-hand-side is always evaluated. Here is the output of the program. Checkout the live example here.
000 0
001 0
010 0
011 0
100 && 0
101 && 0
110 && && 0
111 && && 1
000 || || 0
001 || || 1
010 || 1
011 || 1
100 1
101 1
110 1
111 1
Bottom line: Expression templates and lambdas are both suitable for passing lazy computations to functions. They both can capture local context (variables) and don't extend the life-cycle of the captured argument. Their type is not meant to be observed (it is often unpronounceable). Expression templates, however, are very specific because they appear only in the context of overloaded operators and as a result they may be lot more expressive.

This blog post is motivate by this question on Stackoverflow.

Tuesday, August 26, 2014

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 of a monad. Some background in functional programming may be helpful in reading this post. A good understanding of nested generic lambdas is a must. If you are wondering if you should read the part 1 first, then you probably should.

Ok, lets cut to the chase.
auto list = [](auto ...xs) { 
    return [=](auto access) { return access(xs...); }; 
}; 

auto head = [](auto xs) { 
    return xs([](auto first, auto ...rest) { return first; }); 
}; 

auto tail = [](auto xs) { 
    return xs([](auto first, auto ...rest) { return list(rest...); }); 
}; 

auto length = [](auto xs) { 
    return xs([](auto ...z) { return sizeof...(z); }); 
}; 

int len = length(list(1, '2', "3"));  // 3

list is a generic lambda that accepts a variable number of arguments and returns a closure (an instance of the inner lambda) that captures the arguments by value. The inner lambda accepts a parameter (called access) that must be callable with an arbitrary number of arguments. The inner lambda simply expands the parameter pack while calling the callable. That way it provides "access" to the captured parameter pack.

If you squint a little, you will probably realize that list is like a constructor of a tuple. As a matter of fact, if you were to implement the inner lambda using a good old class template, you will most likely resort to using a std::tuple member.

head, tail, and length are examples of operations that you may perform on a list. head returns the first element, tail returns the list excluding the first element and length returns the size of the parameter pack. For example, a three element list is passed to the length lambda. As every list itself is a closure, it is called with an "accessor" function. The accessor simply does a sizeof... and returns the result, which propagates all the way out.

It is probably immediately apparent that this idiom adds life to otherwise drab variadic parameter packs. Don't get me wrong, variadic parameter packs are cool and we won't have other cool things like std::tuple without them. However, the point is that the language allows very few operations on a parameter pack. In general, you can't "store" them. Pretty much, you can expand a parameter pack, ask for its size, and unwind it using the car/cdr recursive style. And that's about it. Until now, To store a parameter pack you have to put it in a std::tuple.

But now there is an alternative. You can capture it using a lambda and provide access to it as done in the list lambda. As it turns out, this seemingly innocuous and perhaps needlessly convoluted approach to "accessing" parameter packs is phenomenally powerful.

WHY? ... the list lambda and the closure inside are special. Together, they form an implementation of a Continuation Monad.

A great introduction for continuation monad for C++ programmers is here. In essence, the list lambda above takes a value (a variadic parameter-pack) and returns a simple "continuator" (the inner closure). This continuator, when given a callable (called access), passes the parameter pack into it and returns whatever that callable returns.

Borrowing from the FPComplete blogpost, a continuator is more or less like the following.
template<class R, class A>
struct Continuator {
   virtual ~Continuator() {}
   virtual R andThen(std::function<R(A)> access) = 0;
};
The Continuator above is abstract--does not provide an implementation. So, here is a simple one.
template<class R, class A>
struct SimpleContinuator : Continuator<R, A> 
{
   SimpleContinuator(A x) : _x(x) {}
   R andThen(std::function<R(A)> access) {
       return access(_x);
   }
   A _x;
};
The SimpleContinuator accepts one value of type A and passes it on to access when andThen is called. The closure returned by the list lambda is conceptually the same. It is more general. Instead of a single value, the inner closure captures a parameter-pack and passes it to the access function. Neat!

Hopefully that explains what it means to be a continuator. but what does it mean to be a monad? Here is a good introduction using pictures.

The inner closure returned by the list lambda is also a list monad, which is implemented as a continuation monad. Note that continuation monad is the mother of all monads. I.e., you can implement any monad with a continuation monad. Of course, list monad is not out of reach.

As a parameter-pack is quite naturally a "list" (often of heterogeneous types), it makes sense for it to work like a list/sequence monad, where operations can be chained one after another. The list lambda above is a very interesting way of converting C++ parameter-packs to a monadic structure.

The head and length lambdas above, however, are a bit disappointing because they break the monad and the nested lambda inside simply returns a non-monadic value (something you can't chain more operations to). There is arguably a better way to write a chain of "processing" operations as shown below.

Functor

Before we can say that the list lambda is a monad constructor, we have to show that it is a functor. I.e., fmap must be written for the inner closure. Note that "functor" is a category theoretic term. It has no direct correlation with a C++ functor (i.e., a function object)

The list lambda above serves as the creator of the functor from a parameter pack---essentially it serves as the "return" in Haskell. That created functor keeps the parameter-pack with itself (capture) and it allows access to it provided you give a callable that accepts a variable number of arguments. Note that the callable is called EXACTLY-ONCE.

Lets write fmap for such a functor.
    
auto fmap = [](auto func) { 
        return [=](auto ...z) { return list(func(z)...); };
    };
The type of the func must be (a -> b). I.e., in C++ speak,
    template <class a, class b>
    b func(a);
The type of fmap is "fmap: (a -> b) -> list[a] -> list[b]" I.e., in C++ speak,
    

    template <class Func, class a, class b>
    list<b> fmap(Func, list<a>);
I.e., fmap simply maps list-of-a to a list-of-b.
Now you can do
    
    auto twice = [](auto i) { return 2*i; };
    auto print = [](auto i) { std::cout << i << " "; return i;};
    list(1, 2, 3, 4)
        (fmap(twice))
        (fmap(print)); // prints 2 4 6 8 on clang (g++ in reverse)
Therefore, it is a functor.

Monad

Now, lets try to write a flatmap (a.k.a. bind, selectmany)

Type of flatmap is "flatmap: (a -> list[b]) -> list[a] -> list[b]"

I.e., given a function that maps a to a list-of-b and a list-of-a, flatmap return a list-of-b. Essentially, it takes each element from list-of-a, calls func on it, receives (potentially empty) list-of-b one-by-one, then concatenates all the list-of-b, and finally returns the concatenated list-of-b.

Here's an implementation of flatmap for list.
 
    auto concat = [](auto l1, auto l2) {
        auto access1 = [=](auto... p) {
          auto access2 = [=](auto... q) {
            return list(p..., q...);
          };
          return l2(access2);
        };
        return l1(access1);
    };

    template <class Func>
    auto flatten(Func)
    {
      return list(); 
    }
    
    template <class Func, class A>
    auto flatten(Func f, A a)
    {
      return f(a); 
    }
    
    template <class Func, class A, class... B>
    auto flatten(Func f, A a, B... b)
    {
      return concat(f(a), flatten(f, b...));
    }
    
    auto flatmap = [](auto func) {
      return [func](auto... a) { return flatten(func, a...); };
    };
Now you can do a lot of powerful things with a list. For example,
 
    auto pair  = [](auto i) { return list(-i, i); };
    auto count = [](auto... a) { return list(sizeof...(a)); };
    list(10, 20, 30)
        (flatmap(pair))
        (count)
        (fmap(print)); // prints 6.
The count function is a monad-perserving operation because it returns a list of single element. If you really want to get the length (not wrapped in a list) you have to terminate the monadic chain and get the value as follows.
 
    auto len = [](auto ...z) { return sizeof...(z); }; 
    std::cout << list(10, 20, 30)
                     (flatmap(pair))
                     (len); // prints 6
If done right, the collection pipeline pattern (e.g., filter, reduce) can now be applied to C++ parameter-packs. So lets try to do that but first, lets verify the monad laws.

Monad Laws

Let's make sure the list monad satisfies all three monad laws.
    auto to_vector = [](auto... a) { return std::vector<int> { a... }; };
    
    auto M = list(11);
    std::cout << "Monad law (left identity)\n";
    assert(M(flatmap(pair))(to_vector) == pair(11)(to_vector));
        
    std::cout << "Monad law (right identity)\n";
    assert(M(flatmap(list))(to_vector) == M(to_vector));
        
    std::cout << "Monad law (associativity)\n";
    assert(M(flatmap(pair))(flatmap(pair))(to_vector) == 
           M(flatmap([=](auto x) { return pair(x)(flatmap(pair)); }))(to_vector));
All assertions are satisfied.

Collection Pipeline

Although the above list lambda is provably a monad and shares characteristics of the proverbial list-monad, it is quite unpleasant to work with as a collection pipeline. Especially because the behavior of a common collection pipeline combinator filter (a.k.a where) does not meet common expectations.

The reason is just how C++ lambdas work. Each lambda expression produces a function object of a unique type. Therefore, list(1,2,3) produces a type that has nothing to do with list(1) and an empty list, which in this case would be list().

The straight-forward implementation of `where` fails compilation because in C++ a function can not return two different types.
    auto where_broken = [](auto func) {
      return flatmap([func](auto i) { 
          return func(i)? list(i) : list(); // broken :-(
      }); 
    };
In the above implementation, func returns a boolean. It's a predicate that says true or false for each element. The ?: operator does not compile because the types of list(i) and list() (empty list) are different.

So, a different trick can be used to allow continuation of the collection pipeline. Instead of actually filtering the elements, they are simply flagged as such---and that's what makes it unpleasant.
    auto where_unpleasant = [](auto func) {
      return [=](auto... i) { 
          return list(std::make_pair(func(i), i)...);
      }; 
    };
The where_unpleasant gets the job done but unpleasantly... For example, this is how you can filter negative elements.
    auto positive = [](auto i) { return i >= 0; };
    auto pair_print = [](auto pair) { 
      if(pair.first) 
         std::cout << pair.second << " "; 
      return pair; 
    };
    list(10, 20)
        (flatmap(pair))
        (where_unpleasant(positive))
        (fmap(pair_print)); // prints 10 and 20 in some order


Heterogeneous Tuples

So far the discussion was about homogeneous tuples. Now lets generalize it to true tuples. Note that fmap, flatmap, where take only one callback lambda. To provide multiple lambdas each working on one type, we can overload them. For example,
    template <class A, class... B>
    struct overload : overload<A>, overload<B...> {
      overload(A a, B... b) 
          : overload<A>(a), overload<B...>(b...) 
      {}  
      using overload<A>::operator ();
      using overload<B...>::operator ();
    };
     
    template <class A>
    struct overload<A> : A {
      overload(A a) 
          : A(a) {} 
      using A::operator();
    };
    
    template <class... F>
    auto make_overload(F... f) {
      return overload<F...>(f...);   
    }
    
    auto test = 
       make_overload([](int i) { std::cout << "int = " << i << std::endl; },
                     [](double d) { std::cout << "double = " << d << std::endl; });
    test(10); // int 
    test(9.99); // double    
Let's use the overloaded lambda technique to process a heterogeneous tuple continuator.
    auto int_or_string = 
            make_overload([](int i) { return 5*i; },
                          [](std::string s) { return s+s; });
        list(10, "20")
            (fmap(int_or_string))
            (fmap(print)); // prints 50 and 2020 (gcc in reverse)

Finally, Here is the complete live example. For more relevant reading, also see the lambda-over-lambda.

P.S. Why is the order of output not the same across compilers? The order of variadic pack expansion is defined in the standard which corresponds to the original order of the pack. The order of evaluating function argument expressions is, however, not standardized. For example, checkout the implementation of fmap. func(z) is called as many time as there are arguments. However, the order in which multiple calls to func are evaluated is not guaranteed. As the calls to func print the values out to the console, the output is unpredictable across compilers. See more discussion on reddit/r/cpp.

Thursday, May 22, 2014

Using The Pigeonhole Principle in C++ Metaprogramming

The Pigeonhole Principle is one of the most obvious fundamentals in mathematics. It is so obvious that you may be surprised that there is even a name for it. It states that:

"If n items are put into m containers, with n > m, then at least one container must contain more than one item."

Alternatively,

"If there are n items and m containers, with n > m, and only one item can fit in a container, then at least one item must remain out."

For those who prefer visuals and really hate math:


Even though the principle is simple it has been used to prove many complex mathematical theorems and lemmas. Here is one I find quite interesting:

"Incompressible strings of every length exist."

Alternatively,

"There is a file of every size that your favorite zip program can't compress."

The solution is left to the reader as an exercise.

So, does the Pigeonhole Principle show up in programming. Of course it does. That's why std::vector must allocate memory when its capacity is full. OK, but does it manifest in more interesting ways? As it turns out, it has been used in compile-time meta-programming to achieve interesting results. It manifests in preprocessor meta-programming and in template meta-programming in two distinct flavors.

The Pigeonhole Principle in C++ Preprocessor Meta-programming

Check out the following example. Also available here. The original author of this trick is unknown to me.
#include <iostream>

#define COUNT_ARGS(...)     PP_NARG_IMPL(__VA_ARGS__,PP_RSEQ_N()) 
#define PP_NARG_IMPL(...)   PP_ARG_N(__VA_ARGS__) 
#define PP_ARG_N( _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N 
#define PP_RSEQ_N() 10,9,8,7,6,5,4,3,2,1,0 

int main()
{
  std::cout << COUNT_ARGS(a,b,c,d); // prints 4
}
COUNT_ARGS is a "simple" macro that counts the number of variadic arguments it is called with. It does that by using a preprocessing programming trick based on the Pigeonhole principle. Here is how the macro expands:
  1. The COUNT_ARGS macro substitutes the arguments (a,b,c,d) in the __VA_ARGS__ part before calling PP_NARG_IMPL. The PP_RSEQ_N macro is a list of integers from 10 to 0, which is substituted in the PP_NARG_IMPL. Therefore, the PP_NARG_IMPL macro is "called" with actual arguments = a,b,c,d,10,9,8,7,6,5,4,3,2,1,0
  2. The PP_NARG_IMPL macro simply forwards its arguments to the PP_ARG_N macro.
  3. The PP_ARG_N macro is where the Pigeonhole Principle comes in to play. It has 11 named arguments: From _1, _2, _3, etc. and N. Note that _1, _2, etc. are not special. They are just macro arguments with an underscore at the beginning. You may want to rename them as one, two, three, four, etc. It won't make a difference. The PP_ARG_N always expands to its 11th argument because of N.
  4. The original argument list has 15 arguments but there are only 11 arguments to the PP_ARG_N macro. Obviously, not all are going to fit. The PP_ARG_N macro only "picks up" the first actual argument that does not get a slot (i.e., 11th)
  5. As N always coincides with the 11th actual argument, the PP_ARG_N results in that value producing the count.
Needless to say, that's clever! Now let's proceed with template meta-programming.

The Pigeonhole Principle in C++ Template Meta-programming

Check out the following example. Also available here.
int main()
{
 auto x = ::nth<7>(0,"1",'2',3,"4",'5',6,"7");
 std::cerr << x << std::endl;
}
The goal is to access the N-th element in a variadic function argument list. The output of the above program should be 7.

There are many ways to go about implementing it, most using recursion of some sort. However, there is one implementation I came across, which I find particularly interesting. Why? You guessed it ... It uses the Pigeonhole Principle to avoid recursion.

Originally, the code below was posted by Roland Bock on the boost developers mailing list. If you prefer more comments, please see the same example with comments by LJEvans.
#include <utility>
#include <iostream>

namespace detail
{
  struct any { template<typename T> any(T &&) {} };

  template<typename T, typename U> struct first { typedef T type; };

  template<typename ...Ts>
  struct select_impl 
  {
    template<typename U, typename ...Vs>
 static U &&select(typename first<any, Ts>::type..., U &&u, Vs &&...) 
    {
    return static_cast<U&&>(u);
    }
  };

  template<std::size_t... Idx, typename... Ts>
  static auto select(const std::index_sequence<Idx...>&, Ts&&... ts)
  {
     return select_impl<decltype(Idx)...>::select(static_cast<Ts&&>(ts)...);
  }
}

template<std::size_t N, typename ...Ts>
auto nth(Ts &&...ts)
{
  return detail::select(std::make_index_sequence<N>(), static_cast<Ts&&>(ts)...);
}

int main()
{
 auto x = ::nth<7>(0,"1",'2',3,"4",'5',6,"7"); // prints 7
 std::cerr << x << std::endl;
}
Here is how the nth<7>(...) function works in the example above.
  1. N is 7 and Ts is a variadic parameter pack of integers, character strings, and plain characters.
  2. The std::make_index_sequence is a new addition in C++14 that produces an instance of std::index_sequence given a compile-time integral constant. Here, it produces std::index_sequence<0,1,2,3,4,5,6>.
  3. The formal arguments to the nth function (captured in the parameter pack ts) are forwarded to detail::select using a static_cast. This function must return the nth argument among the forwarded arguments.
  4. In detail::select, the Idx parameter pack represents the indices from 0 to 6. Its deduced by the compiler looking at the type of the index_sequence instance.
  5. The select_impl class template is instantiated with the decltype of each member in the Idx parameter pack. decltype(ts)... expands in to a list of types for every member in Ids. In this case, it is just 'int, int, int,... 7 times. The remaining arguments to select_impl::select are just being forwarded as before.
  6. The select_impl::select has access to Ts parameter pack, which is at the class-template level. Recall that it is 'int,int,int,....'. The list of formal arguments to select_impl::select is broken down in to 3 parts: a variadic piece of N-1 arguments at the beginning, U&& in the middle, and everything else in Vs.
  7. The first N-1 arguments to select_impl::select are "absorbed" using the detail::any class. The detail::any has a single argument constructor that converts argument of any type to any. The first N-1 arguments are thus converted to any. In our example, all the arguments from 0 to 6 are converted to any. The conversion is achieved using an in place parameter pack expansion 'typename first::type...'. For every argument in the Ts parameter pack, the 'first' meta-function is applied, which results into the 'any' type every time.
  8. As the first N-1 arguments are out of the way, U&& necessarily fits the N-th argument. This is where the Pigeonhole Principle springs back in to action.
  9. The remaining argument after the N-th (if any) are left unused in the Vs parameter pack.

So, there it is: returning the N-th argument in a argument list without using recursion. In practice, however, std::make_index_sequence is implemented using recursion. So, the above code is not truly recursion-free.

OK ... So you read it all! I'm sure you found the use of the Pigeonhole Principle in processing variadics in C++ very interesting.

Wednesday, May 07, 2014

A tale of noexcept swap for user-defined classes in C++11

C++11 has taken another stab at function exception specifications for the masses. The shiny new ‘noexcept’ keyword is phasing out its zombie cousin ‘throw’. The well accepted guideline for the old exception specification is: "don’t use them!" That’s good for us because now we don’t have to bother (the reasons for not using throw specification aren’t for the faint hearted anyways.) The noexcept feature does not appear to be a walk in a park either. So hold on tight!

noexcept is meta-programmable! a.k.a conditional noexcept. It is possible to conditionally specify functions to throw any exceptions. The noexcept specification of functions can be inspected at compile-time and functions can derive their own noexcept specification based on exception specifications found elsewhere in the program. Meta-programs are not off-limits here. An excellent introduction of the noexcept feature and its history can be found in June’11 Overload Journal and on Andrzej's C++ blog. I won’t repeat that here but a quick motivation is in order.

Compile-time knowledge about a move-constructor that it does not throw (i.e., annotated with noexcept(true)) can be used for improved run-time performance. For example, std::vector<T>::resize, std::vector<T>::reserve automatically use T’s move-constructor instead of a copy-constructor if T's move-constructor does not throw. Moving of T objects instead of copying would likely achieve higher performance. The standard library provides std::move_if_noexcept function that does move only if it is guaranteed to not fail. Otherwise, it simply resorts to copy-construction. More on this can be found here. I'll return to the topic of writing noexcept move-ctor towards the end of this post.

But the post is about swapping, so lets talk about that. Here is how the std::pair::swap is declared in C++11.

void pair::swap(pair& p)
  noexcept(noexcept(swap(first, p.first)) &&
           noexcept(swap(second, p.second)));


It basically says that pair's swap will throw if either swapping of first or second member throws. The swapping of first and second possibly resolve to their own namespace-level swap via ADL or else they simply pick up std::swap (because pair::swap is declared in std namespace). This declaration seems to indicate a few things.

  1. For a user-defined type it is now much more preferable to have its own namespace-level swap overload instead of using vanilla std::swap. The namespace-level swap function, being an extension of the type’s interface, is vastly more efficient and often can be written in way that it does not throw. The std::swap function, on the other hand, may throw because it uses a copy-constructor and copy-assignment operator while swapping two objects. If you are like me, your member copy-assignment operator will use copy-and-swap idiom for strong exception safety. That means std::swap will create and destroy 3 copies. What a waste! Moreover, that increases the chance of throwing. Bottom line: If T has a member swap, a swap function should be added in the same namespace as of T.

  2. There are some assumptions buried in the above reasoning: (1) move-constructor is not available for a user-defined T, and (2) it is possible to implement member swap of T that does not throw and you can actually say so.

  3. As far as move-constructor being not available is concerned, I think, there are large number of C++03 libraries, which will acquire move-semantics slowly than you might desire. Till then std::swap will, unfortunately, use copy-ctor and copy-assign. A legacy class with a copy-ctor won’t get an automatic move-ctor because it would do wrong things.

  4. The noexcept specification of the user-defined swap better be accurate. Can we really write a nothrow member swap and say so confidently? Obviously, it depends on the members of the user-defined type that we’re swapping. To me, it’s all uphill from here.


Lets look at how standard library uses noexcept for some of its own classes. We already saw std::pair before. How about std::tuple, which is a generalization of a struct and that’s why may be user-defined classes should follow the same basic principle. Tuple’s member swap is declared as

void tuple::swap(tuple& rhs) noexcept(see below)
// The expression inside noexcept is equivalent to the
// logical AND of the following expressions:

noexcept(swap(declval<T&>(), declval<T&>()))
// where Ti is ith type in the variadic list of types.


Tuple’s member swap inspects the noexcept specifications of its members’ swap functions and derives its own specification from that. That makes sense. If swapping of any of the member throws, the tuple’s swap throws. The declval function belongs to same clique as std::move, std::forward, etc. It is a way to obtain rvalue reference of a type without using a constructor. It suffices to say that declval<T> returns "T&&" and declval<T&> returns "T & &&", which is the same as "T &."

Consider a typical C++03 user-defined legacy class that manages its own resources.

namespace L 
{
struct legacy 
{
  legacy();                             // Does not throw
  legacy(const legacy &);               // This may throw
  legacy & operator = (const legacy &); // This may throw (strong exception safe)
  ~legacy() throw();                    // Does not throw
  void swap(legacy &) throw();          // Does not throw
};
} // namespace L


The above legacy class is well-designed except for the fact that it does not have any namespace-level swap. To make it a better citizen in C++11, it needs a namespace-level swap. Interestingly enough, there is substantial code out there that has a specialization of the std::swap in the std namespace. Considering the popularity of this anti-pattern, it probably makes sense to add a swap in two places. It is not too much work in the first place and that may help people who always use a qualified swap (std::swap) habitually.

namespace L 
{
  void swap(legacy &, legacy &) noexcept;
}

namespace std 
{
  template <>
  void swap(L::legacy &, L::legacy &) noexcept;
}


Let’s try to use this modernized legacy class in our C++11 class: Modern.

namespace M 
{
struct Modern 
{
  int count;
  std::string str;
  std::array<L::legacy, 5> data;
  /// default-ctor, copy-ctor, copy-assign, move-ctor, move-assign are defined = default.
  void swap(Modern & p) 
    noexcept(noexcept(swap(std::declval<int &>(),
                           std::declval<int &>())) &&
             noexcept(swap(std::declval<std::string &>(),
                           std::declval<std::string &>())) &&
             noexcept(swap(std::declval<std::array<L::legacy, 5> &>(),
                           std::declval<std::array<L::legacy, 5> &>())));
};
} // namespace M


That’s one awful looking swap. My eyes bleed when I look at it.

It is doing exactly the same thing as std::tuple. It simply checks whether swapping two integers, two strings, and two arrays throw or not. If it does, then member swap of Modern throws. You can skip checks for integer swapping but what’s left is not pretty at all.

Note: The text in italics below is not accurate anymore as noted in the comment below. C++11 std::swap uses move-construction and move-assignment internally. As a result, std::swap in C++11 is generally very efficient IF the move-operations are defined and they are really more efficient than their copy counterparts. In such cases, there is little need to write a custom namespace-level swap. However, member swap may still be useful. See the "default-construct-and-swap" technique for implementing a move-constructor below.

Couple of important things to note here:
  1. Because we added namespace-level swap for the L::legacy class, we dodged several problems.If we did not have free swap, the compiler will instantiate std::swap if it is in the scope. Note, however, that vanilla std::swap may throw defeating the purpose of Modern::swap. If no swap is to be found, compiler issues an error.

  2. We hope that swap of std::string and std::array do not throw. As mentioned in [container.requirements.general], std::string::swap does not throw but std::array<T> swap may throw if an unqualified call to swap(T &, T &) throws. Once again, the namespace-level swap will be chosen here, if available. If that does not exist, a specialization of std::swap will be chosen. If none of them exist, std::swap will be instantiated giving our Modern::swap a nothrow(false) specification.

I like my strong exception safety in my little copy-assignment operator so I don’t want my swap to throw but I don’t want my program to std::terminate() if an exception is really thrown. With all that in mind, I would rewrite the swap as follows.

void Modern::swap(Modern &) noexcept 
{
  static_assert(noexcept(swap(std::declval<int &>(),
                              std::declval<int &>())) &&
                noexcept(swap(std::declval<std::string &>(),
                              std::declval<std::string &>())) &&
                noexcept(swap(std::declval<std::array<L::legacy, 5> &>(),
                              std::declval<std::array<L::legacy, 5> &>())), 
                "throwing swap");
  //.... remaining swap code
}


This is not unlike what’s proposed by others but there’s more. The static assert looks awful and looks redundant. There is already a standard library utility that does the same thing: std::tuple. As mentioned before, std::tuple’s swap throws if any member swap throws. We use it here to make our job a lot easier.

void Modern::swap(Modern & that) noexcept 
{
  typedef std::tuple<int, std::string, std::array <L::legacy, 5> > MemberTuple;
  static MemberTuple *t = 0;
  static_assert(noexcept(t->swap(*t)), "throwing swap");
  // .... remaining swap code
}


If you an enthusiastically paranoid C++ programmer, you may want to use conditional noexcept with a little meta-function (is_nothrow_swappable_all) to save typing.

template<typename... T>
struct is_nothrow_swappable_all
{
  static std::tuple<T...> *t = 0;
  enum { value = noexcept(t->swap(*t)) };
};

void Modern::swap(Modern & that) 
   noexcept(is_nothrow_swappable_all<int, std::string, std::array<L::legacy, 5> >::value);


The "remaining swap code" section above is also rather important. The recommended (by Dave and Howard) way to write it is to use unqualified swap but bring std::swap in the scope:

void Modern::swap(Modern & that) 
  noexcept(is_nothrow_swappable_all<int, std::string, std::array<L::legacy, 5> >::value);
{
  using std::swap;
  swap(this->count, that->count);
  swap(this->str, that->str);
  swap(this->data, that->data);
}


The appropriate swap (namespace-level via ADL or std::swap) will be chosen depending upon availability. That’s exactly what tuple’s swap noexcept checker is going to do for us.

Back to the move-constructor, as promised! As mentioned before, noexcept specification of a move-ctor may have performance implications. So you want to get it right. For the M::Modern class we could have defaulted the move-ctor (= default). That will give it a noexcept(false) specification automatically because internally it uses L::legacy’s copy constructor, which throws. As a consequence, std::vector::resize is not as fast as it can be. We can do better.

Implementing a move-ctor using the default-construct-and-swap idiom turns out be quite handy. Default-construct-and-swap does what it says by first delegating to a noexcept default constructor followed by a swap. To implement a noexcept move-ctor this way, you really need to make sure that swap does not throw. As always, you can rely on a conditional noexcept. I'm using std::is_nothrow_constructible type trait to test the obvious!

Modern::Modern(Modern && m) 
  noexcept(std::is_nothrow_constructible<Modern>::value &&
           noexcept(m.swap(m)))
  : Modern()           
{
  swap(m);
}


As long as Modern's default constructor and member swap are noexcept, the move-ctor is noexcept.

Finally, the move-assign operator can be simply implemented as a single swap operation but for some classes that may not be accurate.

Modern::operator = (Modern && m) noexcept
{
  swap(m);
}


Acknowledgements: I want to thank Howard Hinnant (former Library Working Group chair) for reviewing this article and providing me valuable feedback. Any inaccuracies and mistakes left in the article are strictly mine.

Sunday, May 04, 2014

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


Look at some interesting examples of C++11/14 lambdas and how they interact with other language features and libraries. I hope to find some time to add some explanations. See part 1 if you missed it.

  • Associative containers and lambdas
    std::set<int, std::function<bool(int, int)>> 
      numbers([](int i, int j) { return i < j; });
    
  • Recursive Lambdas (see Creating recursive lambdas and returning them too!)
    auto make_fibo() 
    {
      return [](int n) {
        std::function<int(int)> recurse;
        recurse = [&](int n){ 
           return (n<=2)? 1 : recurse(n-1) + recurse(n-2); 
        }; 
        return recurse(n);
      };
    }
    
  • Composable list manipulation (e.g., cpplinq, narl, LEESA)
    Box boxes[] = { ... };
    int sum_of_weights = 
         cpplinq::from_array(boxes)
      >> where([](const Box & box) { 
           return box.color == Color.RED;
         })
      >> select([](const Box & box) {
           return box.get_weight();
         })
      >> sum();
    
    
  • Overloaded Lambdas
    template <class... F>
    struct overload : F... {
      overload(F... f) : F(f)... {}  
    };
    
    template <class... F>
    auto make_overload(F... f) {
      return overload<F...>(f...);   
    }
    
    auto f = 
        make_overload([](int i) { /* print */ },
                      [](double d) { /* print */ });
    f(10); // int 
    f(9.99); // double
    
  • Type Switch (simple pattern matching) (see type_switch.cpp and this paper)
    struct Base { 
      virtual ~Base() {} 
    };
    struct Derived : Base {};
    
    template <class Poly>
    void test(Poly& p) {  
      match(p)(
        [](int i)             { cout << "int";       },
        [](std::string &)     { cout << "string";    },
        [](Derived &)         { cout << "Derived";   },     
        [](Base &)            { cout << "Base";      },    
        otherwise([](auto x)  { cout << "Otherwise"; })
      );  
    }
    Derived d;
    Base &b = d;
    std::string cpptruths = "C++ Truths";
    boost::any something = cpptruths;
    
    test(10);        // int
    test(cpptruths); // string
    test(something); // string
    test(b);         // Derived
    test(9.99);      // Otherwise
    
  • Converting shared_ptr between boost and std (see StackOverflow)
    template <typename T>
    boost::shared_ptr<T> 
    make_shared_ptr(std::shared_ptr<T> ptr) 
    {      
      return boost::shared_ptr<T>(ptr.get(), 
        [ptr](T*) mutable { ptr.reset(); });
    }
    
    template <typename T>
    std::shared_ptr<T> 
    make_shared_ptr(boost::shared_ptr<T> ptr)
    {      
      return std::shared_ptr<T>(ptr.get(), 
        [ptr](T*) mutable { ptr.reset(); });
    }
    
  • In-place parameter pack expansion 
    template <class... T>
    void foreach(T... args) 
    {  
      bool b[] = { [=](){ 
        std::cout << args << "\n"; 
        return true; 
      }()... }; 
    }
    
    foreach(10, 20.2, true);
    
  • Memoization (see original)
    template <typename ReturnType, 
              typename... Args>
    auto memoize(ReturnType (*func)(Args...))
    {
        std::map<std::tuple<Args...>, ReturnType> cache;
    
        return ([=](Args... args) mutable  
        {
            std::tuple<Args...> t(args...);
            if (cache.find(t) == cache.end())                
            {
              std::cout << "not found\n";
              cache[t] = func(args...);
            }
            return cache[t];
        });
    }
    
  • Finally, slides




Monday, March 24, 2014

Why we need compile-time reflection in C++1y

Programs need data. That's a no brainer. Programs are only as good as the data you provide them. Based on what kind of data is consumed, programs can be divided into two broad categories: (1) those that operate on regular data (a file), and (2) those that operate on other programs. The first kind of programs are abundant. Your browser, for instance, is showing you this page--its data. The second kind of programs are more interesting and they are called meta-programs.

Meta-programs need data too. As with the other programs, meta-programs are only as good as the data you provide them. So what do we feed them? ... Well, In C++, more important than 'what' is 'when'. (remember Morpheus?) A C++ program is just a sequence of bits the compiler is trying to understand. So, while the compiler is trying to make sense of your program, most of it gets translated (to assembly) but some of it gets executed. Quite intriguing! We're talking about compile-time meta-programming.

Coming back to the 'what'. We want to be able to feed whatever is available at compile-time: types, members, functions, arguments, namespaces, line numbers, file names, all are a fair game. Less obvious things are relationships among types: convertibility, parent/child, base/derived, container/iterator, friends, and more.

A C++ compiler already has this information but it is not in a form a meta-program can use. So we're in a soup, where we can run programs (at compile-time) but there is no data! So the next question is 'how' do we make the data available to our meta-programs? And that brings me to what I like to call the Curiously Recurring Template Meta-Programming  (CRTMP) pattern.

Curiously Recurring Template Meta-Programming Pattern

The idea is rather general and many have done it successfully before: Make data available to meta-programs without offending the compiler and do something interesting with it.

Let's look at who are the subjects (players) in this pattern. (1) the compiler, (2) the meta-program, and last but not the least is (3) the programmer itself because machines haven't taken over yet and humans still write most of the programs as of today.

The compile-time data must make sense to all three above. Today, C++ programmers, because we don't mind pain, create that data in a form that is understood by the former two. The prime examples are the traits idiom, the type_traits library, and sometimes code generators that parse C++ files and spit out relationships between classes.  For example, LEESA's gen-meta.py script generates typelists (Boost MPL vectors) for classes that contain other classes (think XML data-binding). Effectively it builds a compile-time tree of the XML node types.

When things are not auto generated, we make it palatable to the fellow programmers using macros. To many, macros are as obnoxious as the data they hide/generate but lets move on. There are many examples of super-charged too: Boost SIMD, pre-variadic Boost MPL, smart enumerations, and many more. When macros are used in a clever way (abused!) they really do look like magic. I got a first-hand experience of that while developing the RefleX library.

RefleX is a compile-time reflection-based type modeling in C++ for DDS Topics. It is open-source but you need the RTI Connext DDS to play with it. It essentially transforms your native C/C++ type into a serializable type representation called a TypeObject and marshals your data in what is called a DynamicData object. Note that both, type and data are serialized. There are systems--perhaps many we owe our modern life to--that need to distribute types and data over the network for discovery, interoperability, compatibility, and for other reasons.

Here's an example:


The RTI_ADAPT_STRUCT macro expands to about 120 lines of C++ code, which is primarily reflection information about ShapeType and it can be used at compile-time. It is based on the BOOST_FUSION_ADAPT_STRUCT macro. The macro opens the guts of the specified type to the RefleX library. The meta-programs in RefleX use this "data" to do their business. The reflection information includes member types, member names, enumerations, and other ornaments such as a "key". The point is that the same CRTMP pattern is used to "export" information about a native C++ type.

So, the last two open-source C++ libraries I wrote use the CRTMP pattern: In one, "data" is generated using a Python script and in the other using a macro. CRTMP makes C++ libraries remarkably powerful. The reality is there is nothing novel about it. It is seen everywhere.

The natural step in evolution of a idiom/pattern is first-class language support.  If something is so prevalent, the language itself should absorb it eliminate the crud involved developing and writing CRTMP-based libraries.

That brings us to the main point of this post: Compile-time Reflection. We need it. Period. It's a natural step of evolution from where C++ is now. When available, it will make vast amount of compile-time data available to C++ meta-programs. They will run faster, look nicer, and they will knock your socks off! It is mind boggling what has been achieved using template and preprocessor meta-programming. Compile-time reflection will push it two notches up. So stay tuned for C++1y.

Wednesday, March 12, 2014

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

It's common knowledge that Functional Programming is spreading like a wildfire in mainstream languages. Latest promoted languages: Java 8 and C++, both of which now support lambdas. So, let the lambdas begin! and may the fun be ever on your side. The same text is available in slides form on Slideshare. This blog post and the talk/slides are inspired by JSON inventor Douglas Crockford.

Write an Identity function that takes an argument and returns the same argument.
auto Identity = [](auto x) {
  return x;
};
Identity(3); // 3
Write 3 functions add, sub, and mul that take 2 parameters each and return their sum, difference, and product respectively.
auto add = [](auto x, auto y) {
  return x + y;
}; 
auto sub = [](auto x, auto y) {
  return x - y;
};
int mul (int x, int y) {
  return x * y;
};

Write a function, identityf, that takes an argument and returns an inner class object that returns that argument.
auto identityf = [](auto x) {
  class Inner {
    int x;
    public: Inner(int i): x(i) {}
    int operator() () { return x; }
  };
  return Inner(x);
};
identityf(5)(); // 5

Write a function, identityf, that takes an argument and returns a function that returns that argument.
auto identityf = [](auto x) {
  return [=]() { return x; };
};
identityf(5)(); // 5

Lambda != Closure
  • A lambda is just a syntax sugar to define anonymous functions and function objects. 
  • A closure in C++ is a function object which closes over the environment in which it was created. The line #2 above defines a closure that closes over x.
  • A lambda is a syntactic construct (expression), and a closure is a run-time object, an instance of a closure type. 
  • C++ closures do not extend the lifetime of their context. (If you need this use shared_ptr)
Write a function that produces a function that returns values in a range.
auto fromto = [](auto start, auto finish) {    
  return [=]() mutable {      
    if(start < finish)        
      return start++;      
    else        
      throw std::runtime_error(“Complete");    
  };  
};
auto range = fromto(0, 10); 
range(); // 0
range(); // 1
Write a function that adds from two invocations.
auto addf = [](auto x) {
  return [=](auto y) { 
    return x+y; 
  };
};
addf(5)(4); // 9
Write a function swap that swaps the arguments of a binary function.
auto swap =[](auto binary) {
  return [=](auto x, auto y) {
    return binary(y, x);
  };
};
swap(sub)(3, 2); // -1
Write a function twice that takes a binary function and returns a unary function that passes its argument to the binary function twice.
auto twice =[](auto binary) {
  return [=](auto x) {
    return binary(x, x);
  };
};
twice(add)(11); // 22
Write a function that takes a binary function and makes it callable with two invocations.
auto applyf = [](auto binary) {
  return [=](auto x) { 
    return [=](auto y) {
      return binary(x, y); 
    };
  };
};
applyf(mul)(3)(4); // 12
Write a function that takes a function and an argument and returns a function that takes the second argument and applies the function.
auto curry = [](auto binary, auto x) {
  return [=](auto y) { 
    return binary(x, y);
  };
};
curry(mul, 3)(4); // 12
Currying (schönfinkeling)
  • Currying is the technique of transforming a function that takes multiple arguments in such a way that it can be called as a chain of functions, each with a single argument.
  • In lambda calculus functions take a single argument only.
  • Must know Currying to understand Haskell.
  • Currying != Partial function application
Partial Function Application
auto addFour = [](auto a, auto b, 
                  auto c, auto d) {
  return a+b+c+d;
};
auto partial = [](auto func, auto a, auto b) {
  return [=](auto c, auto d) { 
    return func(a, b, c, d);
  };
};
partial(addFour,1,2)(3,4); //10
Without creating a new function show 3 ways to create the inc function.
auto inc = curry(add, 1);
auto inc = addf(1);
auto inc = applyf(add)(1);
Write a function composeu that takes two unary functions and returns a unary function that calls them both.
auto composeu =[](auto f1, auto f2) {
  return [=](auto x) {
    return f2(f1(x));
  };
};
composeu(inc1, curry(mul, 5))(3) // 20
Write a function that returns a function that allows a binary function to be called exactly once.
auto once = [](auto binary) {    
  bool done = false;    
  return [=](auto x, auto y) mutable {
    if(!done) {        
      done = true;        
      return binary(x, y);      
    }      
    else        
      throw std::runtime_error("once!");     
  };  
};
once(add)(3,4); // 7
Write a function that takes a binary function and returns a function that takes two arguments and a callback.
auto binaryc = [](auto binary) {    
  return [=](auto x, auto y, auto callbk) {
   return callbk(binary(x,y));    
  };  
};
binaryc(mul)(5, 6, inc) // 31
binaryc(mul)(5,6,[](int a) { return a+1; });
Write 3 functions:
  • unit – same as Identityf
  • stringify – that stringifies its argument and applies unit to it
  • bind – that takes a result of unit and returns a function that takes a callback and returns the result of callback applied to the result of unit.
auto unit = [](auto x) { 
  return [=]() { return x; };
};
auto stringify = [](auto x) {    
  std::stringstream ss;
  ss << x;
  return unit(ss.str());
};

auto bind = [](auto u) {    
  return [=](auto callback) {
   return callback(u());    
  };  
}; 
Then verify.
std::cout << "Left Identity "  
          << stringify(15)() 
          << "==" 
          << bind(unit(15))(stringify)()
          << std::endl;

std::cout << "Right Identity " 
          << stringify(5)() 
          << "=="
          << bind(stringify(5))(unit)()
          << std::endl;
Why are unit and bind special? Read more about them here.