
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.