Boost logo

Boost :

Subject: Re: [boost] [Hana] Announcing Hana's formal review next week (June 10th)
From: Oleg Grunin (ogrunin_at_[hidden])
Date: 2015-06-08 16:29:06


Glen Fernandes <glen.fernandes <at> gmail.com> writes:

>
> Dear Boost community,
>
> The formal review of Louis Dionne's Hana library starts Monday, 10th
> June and ends on 24th June.
>

After playing for a few of hours with Hana I take my hat off to Louis
for the impressive feat he accomplished with the library and the
excellent documentation. MPL unlocked a whole new world of C++
programming that few, at the time, suspected existed. I can only hope
that Hana will do the same. But I am not yet certain of it. Maybe it is
due to the heavy paradigm shift which I haven't yet made. In MPL and
Fusion there was a clear distinction between the compile and run-time
worlds (In the former pretty much everything, save for_each, was
compile-time, and in latter all the compile time stuff lived in
result_of namespace ). With Hana that line is fuzzy. I understand that
Louis considers it its big achievement and it may be so but I am not yet
convinced. To me type manipulations (metaprogramming) were always
something that went on between the programmer and the compiler and were
entirely gone from the resulting binary.

Here is a small example that uses an mpl type map and the corresponding
code I put together (likely sub-optimally) using hana:

// hana.cpp
#include <cassert>
#include <string>
#include <array>
#include <boost/lexical_cast.hpp>
#include <iostream>

#ifdef _USE_HANA

#include <boost/hana.hpp>
#include <boost/hana/ext/std/type_traits.hpp>
#else
#include <boost/mpl/map.hpp>
#include <boost/mpl/range_c.hpp>
#include <boost/mpl/inserter.hpp>
#include <boost/mpl/insert.hpp>
#include <boost/mpl/transform.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/alias.hpp>
#endif

#ifndef _USE_HANA

template <typename _Type, typename _Sz>
struct make_arr{
  typedef std::array<_Type, _Sz::value> type;
};
#else
namespace hana = boost::hana;
using namespace boost::hana::literals;
#endif

void run()
{
  static constexpr int map_size = 100;

#ifdef _USE_HANA
  constexpr auto hana_range = hana::range(hana::int_<0>,
hana::int_<map_size>);
  auto hana_inserter = [](auto st_, auto el_){
    return hana::insert(st_, hana::make_pair(el_,
hana::type<std::array<char, decltype(el_)::value>>));
  };
  // create a map of (int_<0>, array<char, 0>)(int_<1>, array<char, 1>),
etc
  /*constexpr*/ auto hana_map = hana::fold.left(hana_range,
hana::make_map(), hana_inserter);
  // Can I use make_pair() here as a metafunction instead of defining my
own inserter?
#else
  typedef mpl::range_c<int, 0, map_size> mpl_range;
  // create a map of (int_<0>, array<char, 0>)(int_<1>, array<char, 1>),
etc
  typedef mpl::transform<
    mpl_range
   ,mpl::pair<mpl::_, make_arr<char, mpl::_> >
   ,mpl::inserter<mpl::map<>, mpl::insert<mpl::_1, mpl::_2> >
>::type mpl_map;
#endif

#ifdef _USE_HANA
  // find the element at index 69;
  /*constexpr*/ auto hana_el_0 = hana_map[hana::int_<69>];
  // instantiate the array
  constexpr decltype(hana_el_0)::type arr = {0};
  static_assert(sizeof(arr, 69), "");
#else
  typedef mpl::at<mpl_map, mpl::integral_c<int, 69>>::type mpl_el_0;
  constexpr mpl_el_0 arr = {0};
  static_assert(sizeof(arr, 69), "");
#endif
}
  
int main(int argc_, char **argv_)
{
  int c = boost::lexical_cast<int>(argv_[1]);
  for(int i = 0; i < c; ++i)
    run();
}

Despite Louis's claims of a significant compile-time speed up with Hana,
I get the following with clang 3.6.0:

$time clang++ -O3 -D_USE_HANA -stdlib=libc++ -std=c++14 hana.cpp -o
hana
real 0m55.233s
user 0m54.190s
sys 0m0.631s

$time clang++ -O3 -stdlib=libc++ -std=c++14 hana.cpp -o mpl
real 0m2.162s
user 0m1.632s
sys 0m0.108s

And at run-time: (run a loop of 10000)

$ time ./hana 100000
real 0m2.834s
user 0m2.825s
sys 0m0.006s

$ time ./mpl 100000
real 0m0.021s
user 0m0.002s
sys 0m0.001s

Which clearly shows that the stuff intended to be purely compile-time
has leaked into the run-time.

Also it appears that Hana lets the compiler swallow all kinds of code
that doesn't appear to have any practical meaning:

I understand (maybe erroneously) that a hana::map can have a useful
application only if its keys are compile-time constructs, and yet I was
able to compile:
make_map(make_pair(1, "one"), make_pair(2, "two"));
and even
make_map(1,2,3);

It's not at all clear to me how the results of such expressions can be
used.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk