A few questions about Phoenix, Boost.Bind, and FC++

Hello, With all the recent discussion about Functional Programming, I thought I'd take a closer look at some of the FP libraries that I haven't really used before, and I started last night by browsing through Phoenix's documentation. This led me to a few questions: Does Phoenix allow side-effects or is it "pure" functional like Fusion and FC++? Does it allow modification of arguments by reference - either builtin references or reference_wrapper? What is the status of the Phoenix msvc port? The documentation seems to indicate that it's possible but not necessarily forthcoming. Is there any immediate plan to make Phoenix interoperable with the coming standard library's std::bind, std::placeholders, std::is_bind_expression, and std::is_placeholder? Regarding Boost.Bind, will it eventually support is_bind_expression? I mean will it treat types for which is_bind_expression is true as full-blown bind sub-expressions? (I know it's a matter of time and work and testing to get this, and I'd be willing to help out, write test cases, whatever's needed.) Also, Peter, weren't you thinking of proposing operator overloads for bind expressions in C++0x? I think you have some already implemented in Boost.Bind. Do you think operator overloads are likely to make it into the final draft? Finally, I noticed the Phoenix documentation cites BLL and FC++ as major influences. I'm fairly familiar with BLL (with its implementation and usage, rather than its history) but not at all familiar with FC++. I hope at least to skim through the documentation over the next few days. However, one thing I noticed right away while reading about Phoenix was that it borrows the term rank-2 polymorphic function from FC++. I'm just learning this terminology, so I'm trying to gain confidence that I understand it. From briefly skimming (McNamara, 2000) in JFP, I'm under the impression that a rank-2 polymorphic function can only have two parametric types, i.e. two template parameters. So, for example, std::make_pair is rank-2 polymorphic, and FC++ has functions that will produce pairs when called with two different types. A rank-n polymorphic function can have arbitrarily many different template parameters; an example would be std::make_tuple. Doesn't Phoenix actually support rank-n polymorphism? For example, isn't the following a rank-3 polymorphic function in Phoenix and couldn't you write similar function objects for higher ranks? struct tupler_ { template<class> struct result; template<class F, class T0, class T1, class T2> struct result<F(T0,T1,T2)> { typedef tuple<T0,T1,T2> type; }; template<class T0, class T1, class T2> tuple<T0,T1,T2> operator()(T0 t0, T1 t1, T2 t2) const { return make_tuple(t0,t1,t2); } }; phoenix::function<tupler_> tupler; One last thing - I noticed that FC++ was submitted for inclusion in Boost a few years back. What ever happened with that? Thanks in advance! Daniel Walker

On Fri, Jun 6, 2008 at 6:16 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
Hello,
[...]
However, one thing I noticed right away while reading about Phoenix was that it borrows the term rank-2 polymorphic function from FC++. I'm just learning this terminology, so I'm trying to gain confidence that I understand it. From briefly skimming (McNamara, 2000) in JFP, I'm under the impression that a rank-2 polymorphic function can only have two parametric types, i.e. two template parameters. So, for example, std::make_pair is rank-2 polymorphic, and FC++ has functions that will produce pairs when called with two different types. A rank-n polymorphic function can have arbitrarily many different template parameters; an example would be std::make_tuple. Doesn't Phoenix actually support rank-n polymorphism? For example, isn't the following a rank-3 polymorphic function in Phoenix and couldn't you write similar function objects for higher ranks?
struct tupler_ { template<class> struct result;
template<class F, class T0, class T1, class T2> struct result<F(T0,T1,T2)> { typedef tuple<T0,T1,T2> type; }; template<class T0, class T1, class T2> tuple<T0,T1,T2> operator()(T0 t0, T1 t1, T2 t2) const { return make_tuple(t0,t1,t2); } }; phoenix::function<tupler_> tupler;
For what I understand, rank-n polymorphism has nothing to do with the number of type parameters but It has to do on the level of "higher order nesting" that still allows polymorphic functions to be used polymorphically. If the previous sentence didn't make sense to you (I would be surprised if it did :) ), I'll try with an example (I'll use C++0x notations) struct times_two { template<class A> auto operator()(A a) -> decltype(a+a) { return a + a; } }; This is polymorphic function which will apply operator+ to a value of any type (for which + is defined, but this is another story). template<class F> int apply_int(F f) { return f(int(2)); } int i = apply_int(times_two()); This is an higher order function which will exploit rank-1 polymorphism. i.e. it takes a polymorphic function but it will treat it monomorphically inside it (as only a value of type int is passed to it. Thus you can change its definition to: int apply_int(std::function<int(int)> f) { return f(int(2)) ; } This is still a rank_1 polymorphic function as you can pass any function to it. Passing a polymorphic function to it will monomorphize it: int i = apply_int(times_two()); AFAIK plain ML only allows monomorphic functions. The reason is that plain Hindely Milner type inference can only do type dedu I think that this is still rank-1 polymorphism: template<typename V> V apply_any(std::function<V(V)> f, V x) { return f(x); } Now the parameter to f is also type parametric, but inside apply_any, f is still treated monomorphically. Rank 2 polymorphism allows a function passed as a parameter to be treated polymorphically: template<typename F> auto apply_poly(F f) -> decltype(std::make_pair(f(2), std::string("hello world"))) { return std::make_pair(f(2), f(std::string("hello world"))); } auto x = apply_poly(times_two()); Note that you cannot write the above function using std::function, as it will cause its bound function to be monomorphized (modulo parameter conversion). A multisignature_function would help though. Rank-3 polymorphism allows passing polymorphic functions as parameters and still threat them as higher order rank-2 polymorphic functions (i.e. they can in turn take a polymorphic function as parameter). You can guess what Rank-4 and more means. Modern functional languages (Haskel, ML dialects) allow rank-2 polymorphism (but, I think, not more) at the cost of requiring some limited amount of type annotations. C++ allows Rank-n polymorphism (i.e. there is no limit on the amount of nesting). The price you pay is no separate compilation (modulo export? but it will probably require some amount of link time compilation), type checking delayed at instantiation time, and of course the amount of type inference that can be done by templates is limited. And yes, both boost.MPL, FC++ and Phoenix actually support rank-n polymorphism. Now, my understanding of all this stuff is spotty at best, so there is some FP expert is around here, it will very likely correct my explanation HTH, -- gpd.

On Fri, Jun 6, 2008 at 1:29 PM, Giovanni Piero Deretta <gpderetta@gmail.com> wrote:
On Fri, Jun 6, 2008 at 6:16 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
Hello,
[...]
However, one thing I noticed right away while reading about Phoenix was that it borrows the term rank-2 polymorphic function from FC++. I'm just learning this terminology, so I'm trying to gain confidence that I understand it. From briefly skimming (McNamara, 2000) in JFP, I'm under the impression that a rank-2 polymorphic function can only have two parametric types, i.e. two template parameters. So, for example, std::make_pair is rank-2 polymorphic, and FC++ has functions that will produce pairs when called with two different types. A rank-n polymorphic function can have arbitrarily many different template parameters; an example would be std::make_tuple. Doesn't Phoenix actually support rank-n polymorphism? For example, isn't the following a rank-3 polymorphic function in Phoenix and couldn't you write similar function objects for higher ranks?
struct tupler_ { template<class> struct result;
template<class F, class T0, class T1, class T2> struct result<F(T0,T1,T2)> { typedef tuple<T0,T1,T2> type; }; template<class T0, class T1, class T2> tuple<T0,T1,T2> operator()(T0 t0, T1 t1, T2 t2) const { return make_tuple(t0,t1,t2); } }; phoenix::function<tupler_> tupler;
For what I understand, rank-n polymorphism has nothing to do with the number of type parameters but It has to do on the level of "higher order nesting" that still allows polymorphic functions to be used polymorphically. If the previous sentence didn't make sense to you (I would be surprised if it did :) ), I'll try with an example (I'll use C++0x notations)
Ah yes. I see now. Thanks! I was reading the bottom of p14 and top of p15 of http://tinyurl.com/6njpbg. I missed that part about the function being called first, and then its result being put into a pair.
<snip>
Rank 2 polymorphism allows a function passed as a parameter to be treated polymorphically:
template<typename F> auto apply_poly(F f) -> decltype(std::make_pair(f(2), std::string("hello world"))) { return std::make_pair(f(2), f(std::string("hello world"))); }
auto x = apply_poly(times_two());
OK, yes. I think this is the important distinction for practical purposes. Monomorphic and rank-1 polymorphic functions are monomorphic at the call site. Rank-n polymorphic functions are polymorphic at the call site. I'm just interested in using these terms for classification purposes, but I don't want to misuse them egregiously with respect to their formal definitions in FP. So, here's how I'd classify various C++ function objects. // monomorphic struct f { int operator()(int); }; // rank-1 polymorphic template<class T> struct g { T operator()(T); }; // rank-n polymorphic struct h { template<class T> T operator()(T); }; That's reasonable, right?
Note that you cannot write the above function using std::function, as it will cause its bound function to be monomorphized (modulo parameter conversion). A multisignature_function would help though.
Just to clarify, for my own understanding as much as anything, if you have a rank-n polymorphic function, you're already good to go. However, if all you have is monomorphic and/or rank-1 polymorphic functions, then multisignature_funciton would be very helpful. This function overload aggregator - call it multisignature_function, overload_function (I'm starting to prefer overload_function to overload_set, now. ;-) ), or whatever - would help to aggregate monomorphic and/or rank-1 polymorphic functions into a single function object that can be used with different argument types, so long as those types are known upfront (i.e. there's not the usual template argument type deduction at the call site - just overload resolution). If you can additionally include rank-n polymorphic functions in the aggregate (and use them polymorphically at the call site with argument type deduction), then that offers more flexibility in the sorts of aggregates you can define.
Rank-3 polymorphism allows passing polymorphic functions as parameters and still threat them as higher order rank-2 polymorphic functions (i.e. they can in turn take a polymorphic function as parameter). You can guess what Rank-4 and more means.
I'm actually having trouble thinking of a practical example of rank-3 usage of a function object. I think it suffices to say the language allows rank-n for templated operator(), though only rank-2 is usual required, at least in the common case.
Modern functional languages (Haskel, ML dialects) allow rank-2 polymorphism (but, I think, not more) at the cost of requiring some limited amount of type annotations.
C++ allows Rank-n polymorphism (i.e. there is no limit on the amount of nesting). The price you pay is no separate compilation (modulo export? but it will probably require some amount of link time compilation), type checking delayed at instantiation time, and of course the amount of type inference that can be done by templates is limited. And yes, both boost.MPL, FC++ and Phoenix actually support rank-n polymorphism.
Now, my understanding of all this stuff is spotty at best, so there is some FP expert is around here, it will very likely correct my explanation
No, this was all very good. I think it helps to get us all on the same page. We don't need to wade too deeply into the minutia of FP language design and whatnot; I'm not interested in drowning! ... only fishing out the good bits. ;-) Daniel Walker

On Fri, Jun 6, 2008 at 9:48 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
On Fri, Jun 6, 2008 at 1:29 PM, Giovanni Piero Deretta
<snip>
Rank 2 polymorphism allows a function passed as a parameter to be treated polymorphically:
template<typename F> auto apply_poly(F f) -> decltype(std::make_pair(f(2), std::string("hello world"))) { return std::make_pair(f(2), f(std::string("hello world"))); }
auto x = apply_poly(times_two());
OK, yes. I think this is the important distinction for practical purposes. Monomorphic and rank-1 polymorphic functions are monomorphic at the call site. Rank-n polymorphic functions are polymorphic at the call site. I'm just interested in using these terms for classification purposes, but I don't want to misuse them egregiously with respect to their formal definitions in FP. So, here's how I'd classify various C++ function objects.
// monomorphic struct f { int operator()(int); };
// rank-1 polymorphic template<class T> struct g { T operator()(T); };
// rank-n polymorphic struct h { template<class T> T operator()(T); };
That's reasonable, right?
Yep. To complete the collection, plain functions are monomorphic, so are pointers to plain functions. Template functions are usually polymorphic, but pointers to them are monomorphic, which is a for form of rank-1 polymorphism.
Note that you cannot write the above function using std::function, as it will cause its bound function to be monomorphized (modulo parameter conversion). A multisignature_function would help though.
Just to clarify, for my own understanding as much as anything, if you have a rank-n polymorphic function, you're already good to go. However, if all you have is monomorphic and/or rank-1 polymorphic functions, then multisignature_funciton would be very helpful.
I think that the problem here is that I have a completely different use case of a multisignature function object than you and Marco do. I want MSF exactly as a substitute for boost::function but that can wrap an arbitrary polymorphic function object and still retain polymorphic behavior. My use cases are: - separate compilation and still retain useful higher order function behaviour. - variadic size (i.e. standard conainers) of (eterogeneous) polymorphic function objects. I.e. I need the same type erasure capability of boost::function. Personally I see no reason for wrapping overload sets (but that just me). As an exercise I've implemented yet another MSF. It is in the fault under Function Objects as msf.cc. It is not complete as it doesn't support everything boost function does (for example no small object optimization nor allocator support), but the hard parts are already there. It is mostly an exercise in preprocessor metaprogramming. What came to my mind when writing it is that all forms of *_any (from boost.any to adobe any_iterator) can be very easily implemented on top of an MSF without no loss of performance, i.e. I think that it is the minimal general type erasure abstraction.
This function overload aggregator - call it multisignature_function, overload_function (I'm starting to prefer overload_function to overload_set, now. ;-) ),
overload_function is better if you want to wrap an overload set in a single function. SMF if you want to emphasize the type erasure behavior.
or whatever - would help to aggregate monomorphic and/or rank-1 polymorphic functions into a single function object that can be used with different argument types, so long as those types are known upfront (i.e. there's not the usual template argument type deduction at the call site - just overload resolution). If you can additionally include rank-n polymorphic functions in the aggregate (and use them polymorphically at the call site with argument type deduction), then that offers more flexibility in the sorts of aggregates you can define.
I see two completely orthogonal fuctionalities here: 1- type erasure with multiple signatures of a single function object 2- aggregating different function objects in a single polymorphic function object *without* any type erasure at all. The first case is covered by an MSF like the one I've created. The second by something Shunsuke's egg::overload (when I saw it it, something finally clicked and I understood why you wanted to put polymorphic signatures in overload sets of MSF: you didn't require type erasure!). I think that Marco's MSF was an hibryd of both: it (always) performed type erasures and it could store different functions. Unfortunately it lacked direct support for polymorphic function objects and stored every function object in the overload set in a different boost::function, making the size of msf explode. I think that the functionality provided by Marco wasn't minimal. Note that with 1 and 2 together you can trivially get the same functionality of Marco's MSF.
Rank-3 polymorphism allows passing polymorphic functions as parameters and still threat them as higher order rank-2 polymorphic functions (i.e. they can in turn take a polymorphic function as parameter). You can guess what Rank-4 and more means.
I'm actually having trouble thinking of a practical example of rank-3 usage of a function object. I think it suffices to say the language allows rank-n for templated operator(), though only rank-2 is usual required, at least in the common case.
I have trouble too ATM. I guess this is why FP languages usually support at most Rank-2. But I'm sure that there might actually be useful use cases for rank-n. [...]
Now, my understanding of all this stuff is spotty at best, so there is some FP expert is around here, it will very likely correct my explanation
No, this was all very good. I think it helps to get us all on the same page. We don't need to wade too deeply into the minutia of FP language design and whatnot; I'm not interested in drowning! ... only fishing out the good bits. ;-)
Yeah, me to. In fact I prefer not to use the term Rank-whathever at all, because I'm sure I' missing subtle details (as types can be polymorphic, I think that rank N polymorphism apply to them too). In C++ Polymorphic function object works just fine. But it was useful in the MSF discussion to describe all the features of all MSF variants. -- gpd

Giovanni Piero Deretta wrote:
I see two completely orthogonal fuctionalities here:
1- type erasure with multiple signatures of a single function object 2- aggregating different function objects in a single polymorphic function object *without* any type erasure at all.
That's what I've been saying for quite a while. MSF tries to do both, but should only provide the first. The second should be another tool, like egg::overload. That kind of tool needs a lot of work alone. I personally do not find egg::overload very satisfying. Lots of macros, separate type definition and usage... A solution like http://groups.google.com/group/comp.std.c++/msg/34b98493a8531d58 seems more elegant to me. The problem being that it's not really possible, because the reflection mechanism used by function objects doesn't allow rewriting their signatures to forward to them. Ideally, a system that works even with polymorphic functions would be best, and if it doesn't require enumerating the signatures (they could be deduced) even better. By the way, is it possible to deduce the constraints of an argument type and apply concept checking with SFINAE within a lambda expression DSEL? Imagine if it was possible to write auto f = overload( _1 + 42, unary_ellipsis(0) ); _1 + 42 would be a function object similar to auto concept IntAddable<typename T> { /* don't really know how return type is to be specified */ operator+(T, int); }; template<IntAddable T> auto foo(T&& t) -> decltype(t + 42) { return t + 42; } and f would be something like template<IntAddable T> auto f(T&& t) -> decltype(t + 42) { return t + 42; } auto f(...) -> decltype(0) { return 0; }

On Sat, Jun 7, 2008 at 12:36 PM, Mathias Gaunard <mathias.gaunard@ens-lyon.org> wrote:
Giovanni Piero Deretta wrote:
I see two completely orthogonal fuctionalities here:
1- type erasure with multiple signatures of a single function object 2- aggregating different function objects in a single polymorphic function object *without* any type erasure at all.
That's what I've been saying for quite a while. MSF tries to do both, but should only provide the first.
The second should be another tool, like egg::overload. That kind of tool needs a lot of work alone.
I personally do not find egg::overload very satisfying. Lots of macros, separate type definition and usage... A solution like http://groups.google.com/group/comp.std.c++/msg/34b98493a8531d58 seems more elegant to me.
Ah yes! I already had that thread bookmarked :)
The problem being that it's not really possible, because the reflection mechanism used by function objects doesn't allow rewriting their signatures to forward to them.
Could you elaborate?
Ideally, a system that works even with polymorphic functions would be best, and if it doesn't require enumerating the signatures (they could be deduced) even better.
By the way, is it possible to deduce the constraints of an argument type and apply concept checking with SFINAE within a lambda expression DSEL?
For all operators that a DSEL implements, it already knows the required concepts (addable, dereferenciable, etc...), so it can remember every possible operation on every placeholder and carry it to the top level expression; then it can use sfinae on the union of all requirements of each placeholder. For more complex stuff (i.e. bind), it would be much harder: I have no idea if you can extract concepts from function signatures arguments as you can with types (at least without some kind registration). In C++ metaprogramming world, types are first class as you can have type variables (i.e. template type arguments), but I still can't see how you can store a concept in a (metaprogramming) variable. -- gpd

Giovanni Piero Deretta wrote:
but I still can't see how you can store a concept in a (metaprogramming) variable.
See this thread maybe: http://thread.gmane.org/gmane.comp.lib.boost.devel/174823/focus=174910

On Sat, Jun 7, 2008 at 3:17 AM, Giovanni Piero Deretta <gpderetta@gmail.com> wrote:
I think that Marco's MSF was an hibryd of both: it (always) performed type erasures and it could store different functions. Unfortunately it lacked direct support for polymorphic function objects and stored every function object in the overload set in a different boost::function, making the size of msf explode.
Well, " making the size of msf explode" it seems to me a little bit on the scary side ;-) Just to clear what we are taking about: For NON polymorphic function objects or standard functions sizeof(msf) = sizeof(boost::function) * num_signatures; For polymorphic function objects sizeof(msf) = sizeof(boost::function) * num_signatures + sizeof(pointer); Note that this is INDEPENDENT of how many function objects you bind, be them standard or polymorphic. A different case is when you explicit ask boost::function to store a COPY of your function object because of semantic purposes, but IMHO it would be an error to consider it a size increase implementation dependent because you explicit asked for a copy. When you don't want to create copies of your objects you can always do that and the size of MSF is always what is reported above. Finally both with standard function objects and with polymorphic function objects you can ask MSF (for semantic purposes) to create only ONE copy of your object, so in ALL the cases the added size, implementation dependent, is just what is written above no more no less. So I would dare to say that IMHO MSF does NOT lack (direct) support for polymorphic function objects. Thanks Marco

On Sat, Jun 7, 2008 at 1:40 PM, Marco Costalba <mcostalba@gmail.com> wrote:
So I would dare to say that IMHO MSF does NOT lack (direct) support for polymorphic function objects.
Just to be (more) clear. IF MSF is considered to "properly support" normal functions and/or function objects THEN MSF "properly supports" also polymorphic function objects Poof: The size difference, implementation dependent, in the two cases is sizeof(pointer) under all cases The forwarding performance difference in the two cases is zero. End of proof :-) Marco

On Sat, Jun 7, 2008 at 1:40 PM, Marco Costalba <mcostalba@gmail.com> wrote:
On Sat, Jun 7, 2008 at 3:17 AM, Giovanni Piero Deretta <gpderetta@gmail.com> wrote:
I think that Marco's MSF was an hibryd of both: it (always) performed type erasures and it could store different functions. Unfortunately it lacked direct support for polymorphic function objects and stored every function object in the overload set in a different boost::function, making the size of msf explode.
Well, " making the size of msf explode" it seems to me a little bit on the scary side ;-)
Just to clear what we are taking about:
For NON polymorphic function objects or standard functions
sizeof(msf) = sizeof(boost::function) * num_signatures;
For polymorphic function objects
sizeof(msf) = sizeof(boost::function) * num_signatures + sizeof(pointer);
Note that this is INDEPENDENT of how many function objects you bind, be them standard or polymorphic.
Yep sorry. It depends only on the number of signatures. It is fine even if not ideal if you use MSF as an overload set: in this case you still need a pointer for every overload, you waste an extra pointer for a vtable for every signature, but it is still the same O(N) space complexity. It will still be unacceptable for my use case, where I have a single function object and multiple signatures: it can be implemented with just a single pointer to the stored object and a single vtable pointer. I plan to store many of these objects (with *many* signatures) in containers, so wasting space is not an option. <good stuff snipped>
Finally both with standard function objects and with polymorphic function objects you can ask MSF (for semantic purposes) to create only ONE copy of your object, so in ALL the cases the added size, implementation dependent, is just what is written above no more no less.
So I would dare to say that IMHO MSF does NOT lack (direct) support for polymorphic function objects.
I forgot you added support the extra pointer to prevent storing a copy of the same function object to every signature. So yes, it does support polymorphic function objects without making multiple copies. But IMHO It seems kludgey that it needs a different boost::function per signature :( -- gpd

Daniel Walker wrote:
Does Phoenix allow side-effects or is it "pure" functional like Fusion and FC++? Does it allow modification of arguments by reference - either builtin references or reference_wrapper?
Yes. Placeholders are substituted with argument references, so you can do this: int i = 0; (++_1)(i); assert(1 == i); Local variables that appear in Phoenix lambdas are captured by value, unless you specify that you want them captured by reference. You can do that with phoenix::ref().
What is the status of the Phoenix msvc port? The documentation seems to indicate that it's possible but not necessarily forthcoming.
MSVC port? Phoenix works on MSVC and always has, AFAIK.
Is there any immediate plan to make Phoenix interoperable with the coming standard library's std::bind, std::placeholders, std::is_bind_expression, and std::is_placeholder?
I don't know. I do know that Phoenix has been ported to Proto in its entirety (by me), and this might be a nice addition for Phoenix v3. <snip lots>
One last thing - I noticed that FC++ was submitted for inclusion in Boost a few years back. What ever happened with that?
It was rejected. I seem to recall people feeling that it wasn't C++-ish enough. -- Eric Niebler BoostPro Computing http://www.boostpro.com

On Fri, Jun 6, 2008 at 2:05 PM, Eric Niebler <eric@boost-consulting.com> wrote:
Daniel Walker wrote:
Does Phoenix allow side-effects or is it "pure" functional like Fusion and FC++? Does it allow modification of arguments by reference - either builtin references or reference_wrapper?
Yes. Placeholders are substituted with argument references, so you can do this:
int i = 0; (++_1)(i); assert(1 == i);
Local variables that appear in Phoenix lambdas are captured by value, unless you specify that you want them captured by reference. You can do that with phoenix::ref().
OK, but I was thinking more of user defined function objects. Something like ... struct f_ { template<class> struct result { typedef void type; }; template<class T> void operator()(T& t) { ++t; } }; int main() { phoenix::function<f_> f; int i = 0; f(i); assert(i == 1); } Actually, I just tried this and the assertion failed. So, I assume user defined function objects are required to be "pure." Why is that?
What is the status of the Phoenix msvc port? The documentation seems to indicate that it's possible but not necessarily forthcoming.
MSVC port? Phoenix works on MSVC and always has, AFAIK.
Well, I just tried a little smoke test with msvc 9, and it appears to work. However, from the documentation at http://tinyurl.com/6pkmtu: "On the other hand, although Phoenix is not yet ported to MSVC, Phoenix uses the same tried and true implementation techniques used by the Spirit framework. Since Spirit has been ported to MSVC by Bruce Florman (v1.1) and by Raghav Satish (v1.3), it is very likely that Phoenix will also be ported to MSVC."
Is there any immediate plan to make Phoenix interoperable with the coming standard library's std::bind, std::placeholders, std::is_bind_expression, and std::is_placeholder?
I don't know. I do know that Phoenix has been ported to Proto in its entirety (by me), and this might be a nice addition for Phoenix v3.
That's cool. If possible I think it would be a good idea.
<snip lots>
One last thing - I noticed that FC++ was submitted for inclusion in Boost a few years back. What ever happened with that?
It was rejected. I seem to recall people feeling that it wasn't C++-ish enough.
From my initial foray into the documentation I'm getting the same feeling.
Thanks! Daniel Walker

Daniel Walker wrote:
OK, but I was thinking more of user defined function objects. Something like ...
struct f_ { template<class> struct result { typedef void type; }; template<class T> void operator()(T& t) { ++t; } };
int main() { phoenix::function<f_> f; int i = 0; f(i);
That creates a lazy function invocation, but doesn't execute it.
assert(i == 1); }
Actually, I just tried this and the assertion failed. So, I assume user defined function objects are required to be "pure." Why is that?
#include <boost/phoenix/core.hpp> #include <boost/phoenix/operator.hpp> #include <boost/phoenix/function.hpp> namespace phoenix = boost::phoenix; struct f_ { template<class> struct result { typedef void type; }; template<class T> void operator()(T& t) { ++t; } }; int main() { using phoenix::arg_names::_1; phoenix::function<f_> f; int i = 0; f(_1)(i); // OK assert(i == 1); int j = 0; //f(j)(); // by value, doesn't compile //assert(j == 0); f(phoenix::ref(j))(); // by ref, OK assert(j == 1); } HTH, -- Eric Niebler BoostPro Computing http://www.boostpro.com

On Fri, Jun 6, 2008 at 4:51 PM, Eric Niebler <eric@boost-consulting.com> wrote:
Daniel Walker wrote:
OK, but I was thinking more of user defined function objects. Something like ...
struct f_ { template<class> struct result { typedef void type; }; template<class T> void operator()(T& t) { ++t; } };
int main() { phoenix::function<f_> f; int i = 0; f(i);
That creates a lazy function invocation, but doesn't execute it.
Haha! Thanks.
assert(i == 1); }
Actually, I just tried this and the assertion failed. So, I assume user defined function objects are required to be "pure." Why is that?
#include <boost/phoenix/core.hpp> #include <boost/phoenix/operator.hpp> #include <boost/phoenix/function.hpp>
namespace phoenix = boost::phoenix;
struct f_ { template<class> struct result { typedef void type; }; template<class T> void operator()(T& t) { ++t; } };
int main() { using phoenix::arg_names::_1; phoenix::function<f_> f;
int i = 0; f(_1)(i); // OK assert(i == 1);
int j = 0; //f(j)(); // by value, doesn't compile //assert(j == 0);
f(phoenix::ref(j))(); // by ref, OK assert(j == 1); }
Very good! Thanks. I hate "pure" functions. ;-) Daniel Walker

Daniel Walker wrote:
Very good! Thanks. I hate "pure" functions. ;-)
IMO, we shouldn't have to hate "pure" functions. There are really nice things you can do with them (e.g. views). I'd hate disallowing none-pure functions though. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

Daniel Walker wrote:
What is the status of the Phoenix msvc port? The documentation seems to indicate that it's possible but not necessarily forthcoming. MSVC port? Phoenix works on MSVC and always has, AFAIK.
Well, I just tried a little smoke test with msvc 9, and it appears to work. However, from the documentation at http://tinyurl.com/6pkmtu:
"On the other hand, although Phoenix is not yet ported to MSVC, Phoenix uses the same tried and true implementation techniques used by the Spirit framework. Since Spirit has been ported to MSVC by Bruce Florman (v1.1) and by Raghav Satish (v1.3), it is very likely that Phoenix will also be ported to MSVC."
:-) That refers to old MSVC 6.5 and 7.0. Phoenix was written before MSVC 7.1. There was a failed attempt to port Phoenix to the old MSVC compilers. That part of the docs should be updated. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

"Daniel Walker" <daniel.j.walker@gmail.com> wrote in message news:a733b05a0806060916r2a0bfb0pef84ae24e54fb268@mail.gmail.com...
Regarding Boost.Bind, will it eventually support is_bind_expression? I mean will it treat types for which is_bind_expression is true as full-blown bind sub-expressions? (I know it's a matter of time and work and testing to get this, and I'd be willing to help out, write test cases, whatever's needed.)
The structure of the current implementation is written with MSVC6/bcc 5.5-class compilers in mind, and it's hard to add new features without breaking something. It's not impossible, but given that there's no real demand for "bind interoperability" and no significant adoption of is_bind_expression and is_placeholder... why should we bother? It's easier to do nothing and wait for std::bind :-)
Also, Peter, weren't you thinking of proposing operator overloads for bind expressions in C++0x? I think you have some already implemented in Boost.Bind. Do you think operator overloads are likely to make it into the final draft?
I gave this some thought and decided that the operator overloads can wait for TR2, if the built-in lambdas do not make them obsolete before they're even proposed. :-)

Daniel Walker wrote:
Hello,
Hi Daniel, sorry if this is late.
With all the recent discussion about Functional Programming, I thought I'd take a closer look at some of the FP libraries that I haven't really used before, and I started last night by browsing through Phoenix's documentation. This led me to a few questions:
Does Phoenix allow side-effects
Yes.
or is it "pure" functional like Fusion
Huh? Fusion also allows side-effects.
and FC++? Does it allow modification of arguments by reference - either builtin references or reference_wrapper?
Yes, both.
What is the status of the Phoenix msvc port? The documentation seems to indicate that it's possible but not necessarily forthcoming.
Phoenix works with all modern C++ compiler. That comment is outdated and refers to MSVC 6 and 7.
Is there any immediate plan to make Phoenix interoperable with the coming standard library's std::bind, std::placeholders, std::is_bind_expression, and std::is_placeholder?
Let's see how it goes. Eric just recently did an amazing port of Phoenix to Proto bumping the version to 3.0. I intend to be active with Phoenix dev soon. ... I believe the rest (rank-2) was already discussed in some of the exchanges. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net
participants (7)
-
Daniel Walker
-
Eric Niebler
-
Giovanni Piero Deretta
-
Joel de Guzman
-
Marco Costalba
-
Mathias Gaunard
-
Peter Dimov