I can not understand what the real benefits of using Boost.Phoenix.
When I use it with Boost.Spirit grammars, it's really useful:
double_[ boost::phoenix::push_back( boost::phoenix::ref( v ), _1 ) ]
When I use it for lambda functions, it's also useful and elegant:
boost::range::for_each( my_string, if_ ( '\\' == arg1 ) [ arg1 = '/' ] );
But what are the benefits of everything else in this library? The documentation says: "Functors everywhere". I don't understand what is the good of it?
Functional programming in C++. It's hard to explain unless you have previously used a language with proper support for functional programming, such as SML. I tried to use Phoenix and found it nice, but very impractical in real-life projects because it greatly increases compilation times, and error messages are awful when you do something wrong. I rememeber getting a few megabytes of errors from GCC when I played with Phoenix. Also, debugging deeply nested template instantiations is a PITA. (Actually, these are also all the arguments against using most of boost.)
Well, its a very powerful lambda language.
I used it to create a prototype for a math-like DSL:
http://code.google.com/p/asadchev/source/browse/trunk/work/cxx/interval.hpp
and many other things:
http://code.google.com/p/asadchev/source/browse/#svn%2Ftrunk%2Fprojects%2Fboost%2Fphoenix
I'll point you out what is the critical difference between Boost.Lambda and Boost.Phoenix:
Boost.Phoenix supports (statically) polymorphic functors, while Boost.Lambda binds are always monomorphic.
(At the same time, in many aspects the two libraries can be combined, so they are not exclusive choices.)
Let me illustrate (Warning: Code not tested.):
Phoenix
In Phoenix a functor can converted into a Phoenix "lazy function" (from http://www.boost.org/doc/libs/1_54_0/libs/phoenix/doc/html/phoenix/starter_kit/lazy_functions.html)
is_odd
is truly polymorphic (as the functoris_odd_impl
). That isis_odd(_1)
can act on anything (that makes sense). For example inis_odd(_1)(2u)==true
andis_odd(_1)(2l)==true
.is_odd
can be combined into a more complex expression without losing its polymorphic behavior.Lambda attempt
What is the closest we can get to this in Boost.Lambda?, we could defined two overloads:
but to create a Lambda "lazy function" we will have to choose one of the two:
Even if we define a template version
we will have to bind to a particular instance of the template function, for example
Neither
f1
norf2
norf3
are truly polymorphic since a choice has been made at the time of binding.(Note1: this may not be the best example since things may seem to work due to implicit conversions from unsigned to long, but that is another matter.)
To summarize, given a polymorphic function/functor Lambda cannot bind to the polymorphic function (as far as I know), while Phoenix can. It is true that Phoenix relies on the "Result Of protocol" http://www.boost.org/doc/libs/1_54_0/libs/utility/utility.htm#result_of but 1) at least it is possible, 2) This is less of a problem in C++11, where return types are very easy to deduce and it can be done automatically.
In fact, in C++11, Phoenix lambdas are still more powerful than C++11 built-in lambdas. Even in C++14, where
templategeneric lambdas are implemented, Phoenix is still more general, because it allows a certain level of introspection. (For this an other things, Joel de Guzman (developer of Phoenix) was and still is well ahead of his time.)Don't look at Boost.Phoenix2.
Evolution of lambda expressions in boost looks like:
Bind -> Lambda, Phoenix2 (as Spirit part) -> Phoenix3 (as separate library, under development).
Result is single lambda-library with polymorphic functors support (others are going to become deprecated).
I have never used Phoenix, but...
From the Phoenix Library docs:
From the Wikipedia article on Functional programming:
So, Phoenix is a library for enabling Functional Programming in C++.
The major interest in Functional Programming these days seems to stem from the perceived advantages in correctness, and performance, due to limiting or eliminating side-effects.
Correctness, because without side-effects, the code that you see is everything going on in the system. Some other code won't be changing your state underneath you. You can much more easily write bug-free code in this sort of environment.
Performance, because without side-effects, the code you write can safely run in parallel, without any resource managing primitives, or atomic-access tricks. Multi-threading can be enabled extremely easily, even automatically, and operate extremely efficiently.