Boost logo

Boost :

Subject: [boost] "Software Development using the C++ Boost Library", book in preparatiion Options
From: Jesse Perla (jesseperla_at_[hidden])
Date: 2010-02-17 12:33:23


Daniel:

As a caveat, I am far from an expert. just a library user focused on
scientific computing in economics... but here are a few more comments that I
hope the experts can correct.

> 2. type erasure: I looked this term up but it seems as if it is similar to
interface/device independent/ programming. In the past we built homemade
Function and used it in combination with OO specialisation with virtual
functions, Now boost Function is so much
> better. Mathematicians and engineers are used to functions and we adopt
the same approach (e.g. using namespaces)

boost::function certainly beats any home-spun solution. But type erasure is
a way to bridge generic programming to give a common *runtime* interface. I
think of it as akin to getting the benefits of dynamic polymorphism with
arbitrary generic types - effectively creating a virtual function
without inheritance. However, just as with dynamic polymorphism it is not
without cost: The boost::function infrastructure puts in a dispatch which
could drastically hurt performance if called in an inner loop (or have
virtually no effect if the function itself is time consuming). The compiler
can't inline the functions, etc.

Also, the term "type erasure" should be taken literally. The functions
which operate on the boost::function are not able to get any information on
the type. For example, a common way to deal with a function and derivatives
is to have a single function object with an operator() and a gradient()
defined. But if you stuff this in a boost::function you lose the
information and can only call a specific overload/template of operator().
 You can see some old, stupid questions I had asked on this mailing list a
while back about this topic:
http://lists.boost.org/boost-users/2009/01/44253.php What I learned
eventually was that I was trying to use type erasure when I didn't need it,
and I was better off sticking with generic programming...

So boost::function is very useful, but you run into the same tradeoffs and
questions as static vs. dynamic polymorphism: If you don't need dynamic
polymorphism, then consider sticking with compile time templates, etc. for
better performance and genericity at the potential cost of code complexity.
 In the case of scientific computing, I find that almost everything is known
at compile time and you are better off keeping the types generic/not using
type erasure. If you are just using boost::function because the types of
the function objects are complicated, consider the alternatives. See my
comments in the previous post on the use of "auto" and "decltype" to make
this manageable.

> 3. Ideally, we would like TR1 and boost to be as seamless as possible.
Check out: http://www.boost.org/doc/libs/1_42_0/doc/html/boost_tr1.html Just
remember that boost::tr1 is intended to be used only if the vendor hasn't
put in a tr1 library.

> 4. Fusion: I think this is useful, especially with Any?

While I have never used "any", I believe these are two different ways to
deal with the problem. Using something like std::vector<boost::any> is
another example of type erasure (just as std::vector<boost::function<double
(double)> > would be). boost::fusion allows you to have a tuple-like vector
of different types, but while retaining type information. The same types of
tradeoffs apply as before... and fusion is only usable if you know the types
at design-time. If you end up converting some of your code away from
boost::function, you may need something like this. On the other hand, it
can be pretty advanced so be careful...

std::tr1::tuple is enough unless you need to apply an operation on the
vector of types. For example, I have often had the case where I had a
vector of functions I needed to evaluate. I was unable to use
boost::function since I needed genericity so I had a boost::fusion::vector
with the various function types. Then to evaluate the functions at the same
point, I used a fusion::for_each, transform, or fold depending on what I
was trying to do. Note that this should have very high performance: The
fusion::for_each ends up doing something akin to loop unrolling at
compiletime, and since I didn't lose any type information everything could
be inlined.

> 7. Numerical integration: I saw this extensive library in Vault. What is
the status?

These don't seem to be in active development. I have used
http://www.coin-or.org/CppAD/ myself. When using AD you will find it
extremely difficult to use boost::function because the function stops being
generic when the type is removed (play with these libraries and you will
understand quickly). This is a perfect example of why you should be wary of
removing type information if you don't need to.

I think that Robert is correct that you should make sure you study and work
with type erasure/generic programming before writing those chapters,
especially if you are intended this to be used for numeric computing.
 Efficiency is critical for these applications and dynamic polymorphism is
often unnecessary. And don't be fooled by the name boost::function: Its
primary purpose is to bridge dynamic polymorphism for generic callable
types, and not to be a placeholder for mathematical functions. While using
it can sometimes simplify code (when auto/decltype are not available), the
cost should be considered. boost::phoenix, lambda, and bind do not erase
type information and I believe all overhead of function adaptation could be
optimized away with these. While a lot of the Template Metaprogramming book
was beyond my needs, I found careful study essential reading(especially
Chapter 9 which covers these topics)

.... and that about exhausts my knowledge. Good luck with the book!


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