Boost logo

Boost :

From: David A. Greene (greened_at_[hidden])
Date: 2001-12-11 12:59:18


I wanted to add some comments from an ordinary Boost
user. Someone who is at least familiar with Loki to
some small degree but who has not had a chance to delve
into MPL. I'd like to give my first impressions. I think
that's important because it's exactly what new users of
Boost/MPL will experience.

The last thing I want to do is fan the flames and create
more division. I am simply stating my experience.

I've snipped some non-obvious stuff. I really dislike the
"quoted" metafunctions. I realize they're needed to satisfy
broken compilers, but it's such a shame that much of the
potential elegance of metaprogramming is lost (at least to
this novice).

I also dislike the fact that lots of little classes have to
be declared just to force GenScatterHierarchy and Fields into
for-loop implementations. It's really not obvious why "reverse
inherit" is needed.

> template <class TList, class QuotedMF>
> struct GenScatterHierarchy {
>
> public:
> typedef boost::mpl::for_each<
> TList // for each type in TList
> , EmptyType // begin with state EmptyType
> , boost::mpl::compose_f_gx_hy<
> ReverseInheritTwoQuoted
> , boost::mpl::identity<boost::mpl::_1>
> , QuotedMF>
> // apply binary metafunctor mapping <oldState, aType>
> // to InheritTwo<unary_function<Unit,aType>::type, oldState>
> >::state type;
> };

By this point I was almost totally dumbfounded. That's a lot of
ugly code to do a conceptually very simple thing. Andrei is right.
Template metaprogramming is more naturally expressed using recursion
because templates define a functional language. I'm reminded of the
ugly transformations from recursion to iteration, or explicity
coding a parser value stack rather than using inherited and
synthesized attributes. Yes, it's possible, but why do it when it
is often much simpler to let things "fall out" naturally? Less
code, fewer bugs.

> 4.2 Fields Implementation
>
> template <int N, class TList, class QuotedMF>
> inline typename ::boost::mpl::unary_function<QuotedMF,
> typename boost::mpl::at<N, TList>::type>::type&
> Fields(typename GenScatterHierarchy<TList, QuotedMF>& obj)
> {
> typedef boost::mpl::for_loop<
> boost::mpl::int_t<N + 1>
> , boost::mpl::lt<boost::mpl::size<TList>::value>
> , boost::mpl::next<boost::mpl::_1>
> , GenScatterHierarchy<TList, QuotedMF>
> , boost::mpl::compose_f_gxy<
> detail::RightParent
> , ::boost::mpl::project1st<boost::mpl::_1,boost::mpl::_2>
> >
> >::executed::state hier;
>
> typedef typename
> ::boost::mpl::unary_function<detail::LeftParent, hier>::type&
> typeref;
> return typeref(obj);
>
> };

Oh my. project1st<_1,...>? next<_1>? If I follow this correctly,
_1 means two different things in the same instantiation! Those
"little classes" show up here. I realize that they perform the
same function as the typedefs in Loki's GenScatterHeirarchy,
but _shouldn't_ they be bundled up with the class? It's unfortunate
that a for-loop implementation requires one to explode what once
was a relatively simple little self-contained package.

> 5. Conclusions
>
> * MPL is quite powerful. In this small example we were able to:

I have no doubt that it is. It's even possible that iteration
is useful for some tasks. However, I don't think it should be
the One True Way.

> * Use reduction (for_each) instead of awkward, non-portable
> pattern matching.

I would instead argue that reduction (at least in this case) is
very much more awkward than recursion. What you're trying to
do maps nicely onto recursion because hierarchies are trees and
trees are recursive structures.

As for non-portability, it's not correct to call something
non-portable because some compilers are broken. Blame the
compiler vendors, not the programmer. We need a better term
for this because non-portability implies something that is
implementation-defined in the standard which is not the
case (AFAIK) for partial specialization and template template
parameters.

> * "Dynamically" compose metafunctions with compose_f_gxy

In your examples the use of composition is not at all obvious.

> * Employ integer based for_loops

Loops could be useful. I don't have enough experience to be
sure. But they're not a catch-all.

> * MPL offers many other facilities not described here

Wish I knew what they were...

> * MPL needs documentation now.

Yes. As it is I cannot spend time scrounging through source code.
Let's get some nice examples. Give me something that maps naturally
onto a loop construct and I'll be more convinced that the overhead
is worth it.

> I believe some mpl naming conventions could
> be improved as well.For me things did seem simpler once I started
> thinking in terms of quoted metafunctions. But the learning curve is
> high.

No doubt.

> * MPL does not rely on template templates or partial
> specialization. It does a pretty good job encapsulating compiler
> limitations. Of course metaprogramming VC 6/7 remains
> somewhat nightmarish, and the port here is still not complete.

What exactly is nightmarish? From your other posts I gather
that your work on porting Loki to MSVC is continuing. I don't
think it's fair to knock Loki because it wasn't coded with
broken compilers in mind. You work shows that it is possible
to maintain a nice recursion interface while still achieving
working code on such platforms.

                            -Dave

-- 
"Some little people have music in them, but Fats, he was all music,
   and you know how big he was."  --  James P. Johnson

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