[announce] Multi signature boost::function v1.0

Hi all, this is the first official version of multi-signature boost::function extension (MSF) pushed to Boost Vault under the name msf-1.0.zip A multi-signature boost:function 'f' allows something like this int foo1(char) { return -1; } char foo2(string) { return 'x'; } f = foo1; f = foo2; assert( f('x') == -1 ); assert( f("hello") == 'x' ); New in this version: - Feature complete: all boost::function API has been naturally extended - Documented and added a tutorial according to boost standards, see tutorial.html - Added a dynamic dispatcher and an object factory examples that use MSF as a building block - Rewritten part of the code to be even simpler and easy to understand - Fixed case of functors with const and/or volatile operator() - Compiler friendly: tested with gcc3.4, gcc4.2, MSVC - No known issues This library extension, although flexible and IMHO powerful is notably very simple and small, so I would like to ask if someone is interested to add this code in some way directly to boost.function Thanks Marco

On Fri, May 9, 2008 at 8:50 PM, Marco Costalba <mcostalba@gmail.com> wrote:
Hi all,
this is the first official version of multi-signature boost::function extension (MSF) pushed to Boost Vault under the name msf-1.0.zip [...] This library extension, although flexible and IMHO powerful is notably very simple and small, so I would like to ask if someone is interested to add this code in some way directly to boost.function
While useful, I do not think this library belongs in boost function (which is monomorphic), but it should be a library of its own. A couple of questions: 1) can you dispatch on the dynamic type of an object? I.e. struct Base { virtual ~Base() {} }; struct A : Base {}; struct B : Base {}; void foo1(A&); void foo2(B&); f = foo1; f = foo2; A a; B b; foo((Base&)a); // calls foo1 foo((Base&)b); // calls foo2 Generalizing this to multiple arguments you of course get multiple dispatch. 2) If I have a polymorphic function object, can I store a single instance of this object and specify multiple signatures? i.e. struct foo_t { template<class T> void(T){...} } foo; f = foo; // foo will respond to all signatures known to f -- gpd

On Sat, May 10, 2008 at 3:17 AM, Giovanni Piero Deretta <gpderetta@gmail.com> wrote:
1) can you dispatch on the dynamic type of an object? I.e.
struct Base { virtual ~Base() {} };
struct A : Base {}; struct B : Base {};
void foo1(A&); void foo2(B&);
f = foo1; f = foo2;
A a; B b; foo((Base&)a); // calls foo1 foo((Base&)b); // calls foo2
Probably you mean f((Base&)a); // calls foo1 f((Base&)b); // calls foo2 Anyway no you can't. But because also boost::function can't I fail to see an inconsistency. Indeed boost::function<int(A&)> f= foo1; f((Base&)a); // calls foo1 <---- COMPILER ERROR: cannot convert parameter 1 from Base to A&
2) If I have a polymorphic function object, can I store a single instance of this object and specify multiple signatures? i.e.
struct foo_t { template<class T> void(T){...} } foo;
Sorry but the line struct foo_t { template<class T> void(T){} } foo; does not compile for me. Probably I'm missing something obvious. I would like to point out a difference in behaviour with operator=() of boost::function In boost::function a relaxed 'compatibility' concept is used, i.e. when assigning a function to a boost::function implicit type conversions are taken in account, as example you can have int foo(long); boost::function<int (int)> f = foo; Because an int argument can be converted to a long and the function foo is considered 'compatible' with f. This cannot be allowed in the multi signature case to avoid ambiguity when there are more then one possible overload (please refer to tutorial for further details). So in case of multi-signature assignment operator= is based on a 'strictly compatible' concept where, generally speaking, argument types must match. In this case user should explicitly state to which function of the overload set to bound foo. Again, please refer to tutorial.html for a detailed explanation on how to do it. Marco

----- Original Message ----- From: "Marco Costalba" <mcostalba@gmail.com> To: <boost@lists.boost.org> Sent: Saturday, May 10, 2008 10:32 AM Subject: Re: [boost] [announce] Multi signature boost::function v1.0
On Sat, May 10, 2008 at 3:17 AM, Giovanni Piero Deretta <gpderetta@gmail.com> wrote:
2) If I have a polymorphic function object, can I store a single instance of this object and specify multiple signatures? i.e.
struct foo_t { template<class T> void(T){...} } foo;
Sorry but the line
struct foo_t { template<class T> void(T){} } foo;
does not compile for me. Probably I'm missing something obvious.
Try with struct foo_t { template<class T> void operator()(T){} } foo; I think that this was the intent of Giovanni Best Vicente

On Sat, May 10, 2008 at 10:43 AM, vicente.botet <vicente.botet@wanadoo.fr> wrote:
Try with struct foo_t { template<class T> void operator()(T){} } foo;
boost::function<void(int)> f = foo; // ok it works, no ambiguity, object is instantiated as foo_t::operator<int>() boost::multi_signature_function:: function<boost::mpl::vector<void(int), void(std::string)> > msf = foo; // error! Ambiguous call <strip> could be void(int) or <strip> void(std::string) msf = f; // this works! no more ambiguity, foo_t is instantiated with T = int So the bottom line is that it does not work because compiler does not know to which internal boost::function to bound foo, because it could be bounded to both boost::function<void(int)> and boost::function<void(std::string)> an "ambiguous call" type error arise...as it should, if I can dare. Replying to a previous message...
This library extension, although flexible and IMHO powerful is notably very simple and small, so I would like to ask if someone is interested to add this code in some way directly to boost.function
While useful, I do not think this library belongs in boost function (which is monomorphic), but it should be a library of its own.
Form boost.function documentation: "Generally, any place in which a function pointer would be used to defer a call or make a callback, Boost.Function can be used instead" Where boost.function naturally models a function, multi-signature boost::function naturally models an overload set In the examples there is the implementation of an object factory that comes out nice and small using MSF. Why? Essentially it boils down to the fact that class constructors are an overload set! I can use boost::function to bound to an object member function, say foo, but if there exist more then one member named foo and I want to bound them all I have to use different named boost::functions, this is not a natural extension. With MSF I model naturally this case because with a single named MSF object I model all the single named foo members of my object. So the bottom line here is: "Where boost.function naturally models a function, multi-signature boost.function naturally models a set of same named functions" Thanks Marco

On Sat, May 10, 2008 at 11:36 AM, Marco Costalba <mcostalba@gmail.com> wrote:
On Sat, May 10, 2008 at 10:43 AM, vicente.botet <vicente.botet@wanadoo.fr> wrote:
Try with struct foo_t { template<class T> void operator()(T){} } foo;
Yep, sorry for the typo :)
boost::function<void(int)> f = foo; // ok it works, no ambiguity, object is instantiated as foo_t::operator<int>()
boost::multi_signature_function:: function<boost::mpl::vector<void(int), void(std::string)> > msf = foo;
// error! Ambiguous call <strip> could be void(int) or <strip> void(std::string)
msf = f; // this works! no more ambiguity, foo_t is instantiated with T = int
So the bottom line is that it does not work because compiler does not know to which internal boost::function to bound foo, because it could be bounded to both boost::function<void(int)> and boost::function<void(std::string)> an "ambiguous call" type error arise...as it should, if I can dare.
Well my idea was that an unconstrained template function object would be bound to all internal boost::functions (in fact this would require MSF to hold N instances of the function objects, in an ideal case it would only hold one instance and have a function pointer per every signature). In fact in this case using operator= makes sense: you use it only one and all signatures are applied to the object in the RHS. I think that in your case, using operator= is confusing because you are not really reassigning the MSF but just adding an overload. What if operator= tries to bind all signatures at once (and thus allows for boost::function like adaptability) and operator+= (or an explicit add member function) is strict and allows to replace a single overload? This might not be what MSF is for, but I was thinking, for example, of something like this: struct visitor { template<class T, class State> void operator(State, T) { /* do something generically using State and T*/ } }; typedef boost::fusion::tuple<int, std::string, double, char> my_seq; void for_each(my_seq&, msf<int, std::string, double, char>); // for_each can now be implemented in another translation unit // and used like this: my_seq f; struct my_state {...} state; // note that with the current implementation we would have N copies // state for_each(f, boost::bind<void>(visitor(), _1, state));
Replying to a previous message...
This library extension, although flexible and IMHO powerful is notably very simple and small, so I would like to ask if someone is interested to add this code in some way directly to boost.function
While useful, I do not think this library belongs in boost function (which is monomorphic), but it should be a library of its own.
Form boost.function documentation:
"Generally, any place in which a function pointer would be used to defer a call or make a callback, Boost.Function can be used instead"
Where boost.function naturally models a function, multi-signature boost::function naturally models an overload set
Actually it is a bit more, because you can have different state for each overload. I would need something in the middle: a single polymorphic closure which can be accessed dynamically with multiple objects. I can of course do this with your MSF by adding another level of indirection, but it seems wasteful. it would be better if it was the reverse (you have to pay for the storage of each signature state only if you need it), IMHO it would be better. -- gpd

On Sat, May 10, 2008 at 6:08 PM, Giovanni Piero Deretta <gpderetta@gmail.com> wrote:
Well my idea was that an unconstrained template function object would be bound to all internal boost::functions
You mean something like this template<int> struct end_seq_tag { typedef int type; }; template<> struct end_seq_tag<-1> { typedef char type; }; template<int n, typename T> void assign(T const& t, int*) { /* first convert to boost::function then add */ *this += boost::function< at_c<n, Signatures>::type >(t); assign<n - 1>(t, (end_seq_tag<n - 1>::type*)0); /* iterate */ } template<int n, typename T> void assign(T const&, char*) {} /* end condition here */ template<typename T> function& operator=(T const& t) { assign<signatures_size - 1>(t, (end_seq_tag<signatures_size - 1>::type*)0); return *this; } I have written fast, probably there is a better way, but just to show the idea. Is this what you mean ?
I think that in your case, using operator= is confusing because you are not really reassigning the MSF but just adding an overload. What if operator= tries to bind all signatures at once (and thus allows for boost::function like adaptability) and operator+= (or an explicit add member function) is strict and allows to replace a single overload?
operator+= is a nice idea, like an explicit set() or add() method. I have been stick to operator=() just to follow boost::function API, but I agree in case of MSF this could be confusing...
Where boost.function naturally models a function, multi-signature boost::function naturally models an overload set
Actually it is a bit more, because you can have different state for each overload. I would need something in the middle: a single polymorphic closure which can be accessed dynamically with multiple objects.
Sorry but the above sentence does not parse for me. I have to think again on what you meant, sorry, but could you better explain what you mean ? It's my fault to be dumb ;-) Thanks Marco

On Sat, May 10, 2008 at 7:39 PM, Marco Costalba <mcostalba@gmail.com> wrote:
On Sat, May 10, 2008 at 6:08 PM, Giovanni Piero Deretta <gpderetta@gmail.com> wrote:
Well my idea was that an unconstrained template function object would be bound to all internal boost::functions
You mean something like this
template<int> struct end_seq_tag { typedef int type; }; template<> struct end_seq_tag<-1> { typedef char type; };
template<int n, typename T> void assign(T const& t, int*) { /* first convert to boost::function then add */
*this += boost::function< at_c<n, Signatures>::type >(t);
assign<n - 1>(t, (end_seq_tag<n - 1>::type*)0); /* iterate */ }
template<int n, typename T> void assign(T const&, char*) {} /* end condition here */
template<typename T> function& operator=(T const& t) { assign<signatures_size - 1>(t, (end_seq_tag<signatures_size - 1>::type*)0); return *this; }
I have written fast, probably there is a better way, but just to show the idea. Is this what you mean ?
Not sure if the code would compile, but, yes, that would be the idea, except for the fact that in my ideal world MSF would have single copy of F.
I think that in your case, using operator= is confusing because you are not really reassigning the MSF but just adding an overload. What if operator= tries to bind all signatures at once (and thus allows for boost::function like adaptability) and operator+= (or an explicit add member function) is strict and allows to replace a single overload?
operator+= is a nice idea, like an explicit set() or add() method. I have been stick to operator=() just to follow boost::function API, but I agree in case of MSF this could be confusing...
Well, in boost::function, operator= replaces the content of the function, which is not true in MSF case. Operator+= might qualify as operator abuse, so an explicit set or add would be better (but personally have no strong opinion on this)
Where boost.function naturally models a function, multi-signature boost::function naturally models an overload set
Actually it is a bit more, because you can have different state for each overload. I would need something in the middle: a single polymorphic closure which can be accessed dynamically with multiple objects.
Sorry but the above sentence does not parse for me. I have to think again on what you meant, sorry, but could you better explain what you mean ? It's my fault to be dumb ;-)
Not sure of what you cannot parse, so I'll try to be as explicitly as possible. * A monomorphic function object is a function object which has a single type for each argument (if any) and a single result type. Think for example of the standard (C++03) binders. In practice the argument types are not strictly fixed, as conversions are allowed, or even are fully templated (for example boost::bind). The important part is that the result type is fixed. You can think of boost::function as a wrapper that erases the exact type of the function object and leaves only the signature. Dispatching to the correct type is done at runtime (via virtual functions or, equivalently, pointer to functions). boost::function works for every monomorphic function object as long as it is CopyConstructible. If the function object has state, it will be correctly stored in the boost::fuction: struct sum_with_double_and_print { typedef void result_type; void operator()(int i) { std::cout << i + state << '\n'; } sum_with_double_and_print(double state_) : state(state_) {} double state; }; boost::function<void(int)> f = sum_with_duble_and_print(0.7); f(10); // prints 10.7 * A polymorphic function object is a functor which works for multiple argument types, and for which the return value type is (meta)function of the argument types. To let client code deduce the result type you should implement the result_of protocol. // a stateless polymorphic function object: struct twice { template<class Sig> struct result; // the result type is simply the argument type, but in principle it can be an // arbitrary function of the argument type. template<class T> struct result<twice(T)> { typedef T type; }; template<class T> T operator()(T f) { return f + f; } }; std::cout << twice()(10); // print 20 std::cout << twice()(std::string("hello")); // print "hellohello" You can (meta)compute the result type of a polymorphic function object using boost::result_of: boost::result_of<twice(int)>::type i; // i is an int boost::result_of<twice(std::string)>::type j ;// j is a string. i = twice()(10); j = twice()(std::string("hello"); Now, what if I want to erase the actual type of the function object? If I use boost::function I have to fix the argument type: boost::function<int(int)>f1= twice(); f1(10); // ok, returns 20 f1(10.7); // bad, returns 20 again! f2(std::string("hello")); // doesn't even compile! which means that the function object is no longer polymorphic. Well, i can pass an int to f1 and it will (kind of) work, but it will certainly no longer work for std::string. That's where a multisignature function object would help: boost::msf_function<double(double), int(int), std::string(std::string)> f2 = twice(); // magic here! f2(10); // ok: 20 f2(10.7); // ok: 21.4 f2(std::string("hello")); // great: "hellohello" I.e. MSF is the natural extension of boost::function in the realm of polymorphic function objects (well, you still have to choose beforehand the types you want to work with, but it is still much better than boost::function). [ BTW, by a quick at the code of MSF you do not seem to implement the result_of protocol. You definitely should, as MSF is definitely a polymorphic function object,] Currently your interface does not support directly binding a polymorphic function object to all signatures, but as you shown, it can be done easily. Still your current implementation has a problem. You can of course have statefull polymorphic function objects: struct frob { template<class Sig> struct result; template<class T> struct result<frob(T)> { // this is technically not correct, it should be decltype(int() + T()) // which for now should use some kind of promotion traits. typedef T type; }; template<class T> T operator()(T i) { return i + state++; } fromb(int state_) : state(state_) {} int state; }; frob(10) x; x(10); // returns 20 x(10); // returns 21 x(10); // returns 22 x(10.42); // returns 23.42 x(my_big_int(231211251414whatever)); // returns.. well, you got it right? If I put frob in a MSF : msf_function<int(int), double(double), my_big_int(my_big_int)> x = frob(10); it has two downsides ... 1) it does N dynamic allocations, one for each signature. 2) it has N copies of 'frob::state', which for a small object as an int it is not a problem, but in principle it can be wasteful ... and a serious problem: As there are n different states, the increment is separate for each type, and not for all of them: x(10); // returns 20 x(10); // returns 21 x(10); // returns 22 x(10.42); // returns 20.42 !!! x(my_big_int(10)); // returns (my_big_int)21 ! In practice MSF acts as N different boost::function objects with a think type based dispatcher. I can of course fix the problem by adding another layer of indirection: struct frobp { // forward template<class S> struct result : frob::result<S> {}; frob(int i) : p(new frob(i)) {} boost::shared_ptr<frob> p; template<class T> T operator()(T i) { return (*p) (i); } } msf_function<int(int), double(double), my_big_int(my_big_int)> x = frobp(10); Which is ugly, verbose, and ineficient. What I want is MSF to hold a *single* instance of my function object and add to the dynamic dispatching layer one operator() for each of the registered functions (whether this is done via function pointers or virtual functions doesn't matter). In practice this means that you cannot use boost::function for the implementation of MSF (but you might reuse some of its implementation). Note that the old behaviour (one instance for every signature type), can be implemented easily on top of my preferred design, without loss of efficiency. HTH, -- gpd
Thanks Marco _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

On Mon, May 12, 2008 at 6:39 PM, Giovanni Piero Deretta <gpderetta@gmail.com> wrote:
I have written fast, probably there is a better way, but just to show the idea. Is this what you mean ?
Not sure if the code would compile, but, yes, that would be the idea, except for the fact that in my ideal world MSF would have single copy of F.
I was able to implemented in my private trunk the recursive assignment, called set_all() in a much simpler way than the above, due to how MSF is structured. Indeed the set_all() code ends up to a couple of very trivial lines: template<typename Fun> void set_all(Fun const& fun) { boost_fun = fun; Base::set_all(fun); } If you want I can send you the new msf.zip code directly, or do you prefer I update the Vault file ? msf-1.0 -> msf-1.1 ? BTW also the problem of extra copy of boost::function is fixed.
I think that in your case, using operator= is confusing because you are not really reassigning the MSF but just adding an overload. What if operator= tries to bind all signatures at once (and thus allows for boost::function like adaptability) and operator+= (or an explicit add member function) is strict and allows to replace a single overload?
operator+= is a nice idea, like an explicit set() or add() method. I have been stick to operator=() just to follow boost::function API, but I agree in case of MSF this could be confusing...
Well, in boost::function, operator= replaces the content of the function, which is not true in MSF case.
In MSF it's true only for functions with same signature: int foo1(char); int foo2(char); f = foo1; f('x'); // foo1 is called f = foo2; // foo2 overwrites foo1 as does boost.function f('x'); // now foo2 is called
Operator+= might qualify as operator abuse, so an explicit set or add would be better (but personally have no strong opinion on this)
Well set() is already implemented and it works also with the msf code you (probably) have downloaded. It is just that is not a documented API. This is because boost.function that used to have set(), has discouraged and then removed that API. BTW MSF implementation _really_ needs set() and not only operator=(), because for SFINAE to work I need an additional (hidden) argument for each assignment call. Indeed if you look at overload.hpp, operator=() implementation is just: template<typename Fun> function& operator=(Fun const& f) { this->set(f); return *this; } And set() is a public method so it is usable directly by the user.
Not sure of what you cannot parse, so I'll try to be as explicitly as possible.
Thanks for your explanation, I will comment on this in a separated e-mail Thanks Marco

AMDG Marco Costalba wrote:
BTW MSF implementation _really_ needs set() and not only operator=(), because for SFINAE to work I need an additional (hidden) argument for each assignment call. Indeed if you look at overload.hpp, operator=() implementation is just:
template<typename Fun> function& operator=(Fun const& f) { this->set(f); return *this; }
And set() is a public method so it is usable directly by the user.
For everything but constructors, you can use SFINAE on the return type. template<typename Fun> typename boost::enable_if<..., function&>::type operator=(Fun const& f); In Christ, Steven Watanabe

Steven Watanabe wrote:
For everything but constructors, you can use SFINAE on the return type.
... and implicit conversion operators. With constructors you have a work-around (SFINAE on an extra defaulted argument), but with implicit conversion operators, you're out of luck. Can't wait for concepts. Hurry up, Doug. ;-) -- Eric Niebler Boost Consulting www.boost-consulting.com

Marco Costalba wrote:
Giovanni Piero Deretta wrote:
Marco Costalba wrote:
Giovanni Piero Deretta wrote:
I think that in your case, using operator= is confusing because you are not really reassigning the MSF but just adding an overload. What if operator= tries to bind all signatures at once (and thus allows for boost::function like adaptability) and operator+= (or an explicit add member function) is strict and allows to replace a single overload?
operator+= is a nice idea, like an explicit set() or add() method. I have been stick to operator=() just to follow boost::function API, but I agree in case of MSF this could be confusing...
Well, in boost::function, operator= replaces the content of the function, which is not true in MSF case.
In MSF it's true only for functions with same signature:
That's not the same thing. I think Giovanni was pointing out that operator= normally replace all of the content of boost::function... or anything else for that matter. I think this is important. I like the idea of providing an assign() for a sequence of callable objects implementing each signature. However, operator= should retain its usual semantics of assigning the Whole thingy on the lhs and not merely an element of the thingy when the lhs is some sort of aggregate, which your multi-signature function is. <snip>
Operator+= might qualify as operator abuse, so an explicit set or add would be better (but personally have no strong opinion on this)
Well set() is already implemented and it works also with the msf code you (probably) have downloaded. It is just that is not a documented API. This is because boost.function that used to have set(), has discouraged and then removed that API.
I think it would be better to replace set() with insert() (or if you required the overload signature sequence to support random access, you could do something like at()). Your function object is, in a way, a collection of functions - an overload set - so it makes sense for it to act like familiar containers. Actually, you could literally call it boost::overload_set (after std::set and std::multiset) or with the random access requirement you could call it boost::overload_vector (after std::vector). You could call it boost::multifunction, but following std::multimap, std::multiset, etc. that makes me think of one signature mapped to multiple functions, which doesn't make sense. Regardless, I would look for opportunities to merge the STL APIs (concepts) for function objects and containers. Daniel Walker

On Mon, May 12, 2008 at 7:39 PM, Giovanni Piero Deretta <gpderetta@gmail.com> wrote:
I.e. MSF is the natural extension of boost::function in the realm of polymorphic function objects (well, you still have to choose beforehand the types you want to work with, but it is still much better than boost::function).
[ BTW, by a quick at the code of MSF you do not seem to implement the result_of protocol. You definitely should, as MSF is definitely a polymorphic function object,]
IOW you mean that given typedef boost::msf_function<double(double), int(int),std::string(std::string)> MSF; The implementation should lead to... boost::result_of<MSF(double)>::type i; // i is a double boost::result_of<MSF(int)>::type i; // i is an int boost::result_of<MSF(std::string)>::type i; // i is a std::string Is this correct?
Still your current implementation has a problem.
--strip----
msf_function<int(int), double(double), my_big_int(my_big_int)> x = frob(10);
it has two downsides ... 1) it does N dynamic allocations, one for each signature.
well, a boost::function is allocated (empty) on the stack because it's a member data.
2) it has N copies of 'frob::state', which for a small object as an int it is not a problem, but in principle it can be wasteful
... and a serious problem: As there are n different states, the increment is separate for each type, and not for all of them:
This is more a "behaviour" then a problem, as example I can have a state named calls_counter that counts how many time an operator() has been called for each different type of arguments. In this case having separate state is a need: T operator()(T i) { calls_counter++; ...do something.... return some_value; } The real problem IMHO is that this behaviour is not well documented, I'll fix this.
In practice MSF acts as N different boost::function objects with a think type based dispatcher. I can of course fix the problem by adding another layer of indirection:
Have you tried to fix it with msf_function<int(int), double(double), my_big_int(my_big_int)> x; x = boost::ref( frob(10) ); Indeed boost::function supports ref() and cref() to avoid the copy when is not needed or when the copy is simply wrong. MSF supports ref() and cref() too and forwards them, still wrapped, to the underlying boost::function objects so that no copy of the wrapped polymorphic function object is made. Thanks Marco

On Tue, May 13, 2008 at 3:11 PM, Marco Costalba <mcostalba@gmail.com> wrote:
On Mon, May 12, 2008 at 7:39 PM, Giovanni Piero Deretta <gpderetta@gmail.com> wrote:
I.e. MSF is the natural extension of boost::function in the realm of polymorphic function objects (well, you still have to choose beforehand the types you want to work with, but it is still much better than boost::function).
[ BTW, by a quick at the code of MSF you do not seem to implement the result_of protocol. You definitely should, as MSF is definitely a polymorphic function object,]
IOW you mean that given
typedef boost::msf_function<double(double), int(int),std::string(std::string)> MSF;
The implementation should lead to...
boost::result_of<MSF(double)>::type i; // i is a double boost::result_of<MSF(int)>::type i; // i is an int boost::result_of<MSF(std::string)>::type i; // i is a std::string
Is this correct?
Exactly! MSF should support it.
Still your current implementation has a problem.
--strip----
msf_function<int(int), double(double), my_big_int(my_big_int)> x = frob(10);
it has two downsides ... 1) it does N dynamic allocations, one for each signature.
well, a boost::function is allocated (empty) on the stack because it's a member data.
boost::function in most cases does an internal allocation. If I follow the implementation correctly (which of course might not be:) ) , I think that MSF contains a boost::function for every possible signature. For funciton pointers this shouldn't be a problem because boost::function is optimized for small objects, but for more consistent functors it might require a fair number of allocations.
2) it has N copies of 'frob::state', which for a small object as an int it is not a problem, but in principle it can be wasteful
... and a serious problem: As there are n different states, the increment is separate for each type, and not for all of them:
This is more a "behaviour" then a problem,
It is a problem only if one expects that behavior. The current implementation isn't necessarily wrong, but I think that is surprising, since MSF wants to be an obvious extension to boost::function.
as example I can have a state named calls_counter that counts how many time an operator() has been called for each different type of arguments. In this case having separate state is a need:
T operator()(T i) {
calls_counter++;
...do something....
return some_value; }
My point is that you get the separate objects behavior from the same object behaviour at no extra cost, while the reverse is impossible. This is why I think that the 'same object' behavior is more fundamental (and IMHO the expected) and it is what MSF should implement.
The real problem IMHO is that this behaviour is not well documented, I'll fix this.
In practice MSF acts as N different boost::function objects with a think type based dispatcher. I can of course fix the problem by adding another layer of indirection:
Have you tried to fix it with
msf_function<int(int), double(double), my_big_int(my_big_int)> x;
x = boost::ref( frob(10) );
Indeed boost::function supports ref() and cref() to avoid the copy when is not needed or when the copy is simply wrong. MSF supports ref() and cref() too and forwards them, still wrapped, to the underlying boost::function objects so that no copy of the wrapped polymorphic function object is made.
This has different semantics from what I wanted. I do not want to have to keep the wrapped object in the stack to add it in a wrapper. In this case I need I want MSF to copy my object (i.e. to manage its lifetime) but I want it to do only one copy (usually for efficiency, but sometimes like this case, for correctness).
Thanks
Thanks to you. I think that MSF might be a valid addition to boost. -- gpd

On Tue, May 13, 2008 at 3:01 PM, Giovanni Piero Deretta <gpderetta@gmail.com> wrote:
In practice MSF acts as N different boost::function objects with a think type based dispatcher. I can of course fix the problem by adding another layer of indirection:
Have you tried to fix it with
msf_function<int(int), double(double), my_big_int(my_big_int)> x;
x = boost::ref( frob(10) );
Indeed boost::function supports ref() and cref() to avoid the copy when is not needed or when the copy is simply wrong. MSF supports ref() and cref() too and forwards them, still wrapped, to the underlying boost::function objects so that no copy of the wrapped polymorphic function object is made.
This has different semantics from what I wanted. I do not want to have to keep the wrapped object in the stack to add it in a wrapper. In this case I need I want MSF to copy my object (i.e. to manage its lifetime) but I want it to do only one copy (usually for efficiency, but sometimes like this case, for correctness).
Actually currently MSF does not copy anything, takes the functor object as const& and forwards to boost::function It's the default implementation of boost::function that takes the functors by value instead of by reference. See point 4 of boost::function FAQ http://www.boost.org/doc/libs/1_35_0/doc/html/function/faq.html If I have understood correctly you would like that wrapping in a boost::ref would be done internally in MSF, something like template<typename F> void set_all(F const& f) { F& stored_object_copy = store_a_copy_somewhere(f); do_set_all(boost::ref( stored_object_copy )); } Is it correct? And in this case what is your suggestion for an API to fallback on the (currently default and more natural at least by an implementation point of view) N copy behaviour? Thanks Marco P.S: BTW I've tested the use of boost::ref() to fix the single state problem: it works nicely and easily ;-)

On Tue, May 13, 2008 at 7:59 PM, Marco Costalba <mcostalba@gmail.com> wrote:
On Tue, May 13, 2008 at 3:01 PM, Giovanni Piero Deretta <gpderetta@gmail.com> wrote:
In practice MSF acts as N different boost::function objects with a think type based dispatcher. I can of course fix the problem by adding another layer of indirection:
Have you tried to fix it with
msf_function<int(int), double(double), my_big_int(my_big_int)> x;
x = boost::ref( frob(10) );
Indeed boost::function supports ref() and cref() to avoid the copy when is not needed or when the copy is simply wrong. MSF supports ref() and cref() too and forwards them, still wrapped, to the underlying boost::function objects so that no copy of the wrapped polymorphic function object is made.
This has different semantics from what I wanted. I do not want to have to keep the wrapped object in the stack to add it in a wrapper. In this case I need I want MSF to copy my object (i.e. to manage its lifetime) but I want it to do only one copy (usually for efficiency, but sometimes like this case, for correctness).
Actually currently MSF does not copy anything, takes the functor object as const& and forwards to boost::function
Which holds a copy of the functor. It is not a problem of parameter passing, what matter is the number of long lived copies of my functor that end up being stored inside MSF. IMHO the user will expect only one copy of the functor to be stored.
It's the default implementation of boost::function that takes the functors by value instead of by reference.
See point 4 of boost::function FAQ
http://www.boost.org/doc/libs/1_35_0/doc/html/function/faq.html
If I have understood correctly you would like that wrapping in a boost::ref would be done internally in MSF, something like
template<typename F> void set_all(F const& f) { F& stored_object_copy = store_a_copy_somewhere(f);
do_set_all(boost::ref( stored_object_copy )); }
Is it correct?
Yes, these are the semantics i want, but I wouldn't implement it this way. boost::function just get in the way and needlessly complicates the implementation.
And in this case what is your suggestion for an API to fallback on the (currently default and more natural at least by an implementation point of view) N copy behaviour?
I think that this is such a rarely needed behaviour that MSF shouldn't provide an explicit API for it. Do you have a real use case for storing a per signature copy of each function object? The user can implement it if he wants: // warning: untested code :) namespace bf = boost::fusion; typedef mpl::vector<int(int), double(double), std::string(std::string)> sig_vector // assume we have stateful functor types IntToInt, DoubleToDouble, StringToString // which we want to store in a MSF typedef mpl::vector<IntToInt, DoubleToDouble, StringToString> f_vector; // a sequence of all typedef mpl::zip_view< mpl::vector<sig_vector, f_vector> > zipped; // Compute the fusion map from signatures to functors. We do it programmatically, but for simple // problems it might not worth it and just be defined statically. // (might have gotten the order wrong) typedef mpl::fold<zipped, bf::map<>, mpl::unpack_args< mpl::push_back<bf::pair<_1, _2 > > > function_map; struct forward { function_map map; template<typename T> T operator()(T x) { return fl::at_key<T(T)>(map)(x); } }; typedef msf<sig_vector> my_msf; my_msf f = forward(); // magic! This is actually more efficient of using multiple boost::functions, because you will have at most one dynamic memory allocation. Complex? Maybe, but I think that this is so rarely needed that it is not worth supporting out of the box (it might make a nice example though) Note that with my preferred inteface, adding a whole overload set of functions is trivially easy: void foo(int); void foo(double); // test ADL namespace my_namespace { class my_class; void foo(my_class) }; // ADL, again class my_other_class { friend void foo(my_other_class) {...} }; typedef mpl::vector<void(int), void(double), void(my_namespace::my_class), void(my_other_class)> sig_vectorl typedef msf<sig_vector> my_msf; // Adding all foo overloads for sig_vector, using current MSF behaviour struct add_sig { template<class SigP> void operator()(SigP, my_msf& f) { // assuming the static is not anbiguous f = static_cast<SigP>(&foo); } }; my_msf f; // sizeof(f) == O( sizeof(boost::function) * N ) mpl::for_each<sig_vector, boost::add_pointer>(boost::bind(add_sig(), _1, boost::ref(f))); // adding all overloads, If I can get it my way :) struct foo_fwd { template<typename T> void operator()(T x) { foo(x); } }; my_msf f = foo_fwd(); //sizeof(f) = O( sizeof(boost::function) ) Comments? Did I convince you? ;) -- gpd

On Tue, May 13, 2008 at 9:32 PM, Giovanni Piero Deretta <gpderetta@gmail.com> wrote:
// adding all overloads, If I can get it my way :) struct foo_fwd { template<typename T> void operator()(T x) { foo(x); } };
my_msf f = foo_fwd(); //sizeof(f) = O( sizeof(boost::function) )
Comments? Did I convince you? ;)
Yes ;-) I'll stick to one_copy_only behaviour for set_all() But because to implement the N copy case is trivially simple (much simpler then your example) I would like to change the signature of set_all in the following way template<typename Fun> void set_all(Fun const& fun, bool multi_instance = false); Regarding the sizeof(f) == O( sizeof(boost::function) * N ) problem, given that - boost::function object are member data, so allocated on the stack - boost::function object are empty at instantation - boost::function object are created at MSF instantation (seldom event or not in critical loop context?), not during assignment (more often event, more performance critical ? ) I would like to know if - boost::function default c'tor does some allocation? An empty boost::function is cheap to create ? - When a functor is assigned by reference with boost::ref boost::function just copies a pointer/reference ? If the above it's true, but I am not an expert of boost::function, the problem of allocation of N boost::function perhaps is more theoretical then real, also the size problem, given that boost::function requires just 3 pointers does not seem a biggie IMHO. BTW remember the resul_of implementation request?
// a stateless polymorphic function object: struct twice { template<class Sig> struct result;
// the result type is simply the argument type, // but in principle it can be an // arbitrary function of the argument type. template<class T> struct result<twice(T)> { typedef T type; };
template<class T> T operator()(T f) { return f + f; } };
The bad news is that for a polymorphic function object implementation of struct resut is not trivial, MSF takes a sequence of signatures as template parameter! so implementing template<class T> struct result<msf(T)> { ????? }; for something like msf<mpl::vector<int(int), char(double, float), a_class(my_namespace::my_class), void(my_other_class, int, int, int)> does not seem immediate. The good news is that I've done it ;-) and the thing I'm proud of is that implementation does NOT require any metaprogramming stuff dealing with sequences and with building/splitting and comparing signatures and even does not require any argument-arity dependant new specializations apart from what is already present. So no new argument arity dependant code bloat!!! It is very simple, I even don't believe it can work...but it does :-) Marco

On Tue, May 13, 2008 at 11:11 PM, Marco Costalba <mcostalba@gmail.com> wrote:
On Tue, May 13, 2008 at 9:32 PM, Giovanni Piero Deretta <gpderetta@gmail.com> wrote:
// adding all overloads, If I can get it my way :) struct foo_fwd { template<typename T> void operator()(T x) { foo(x); } };
my_msf f = foo_fwd(); //sizeof(f) = O( sizeof(boost::function) )
Comments? Did I convince you? ;)
Yes ;-) I'll stick to one_copy_only behaviour for set_all()
But because to implement the N copy case is trivially simple (much simpler then your example) I would like to change the signature of set_all in the following way
template<typename Fun> void set_all(Fun const& fun, bool multi_instance = false);
Regarding the sizeof(f) == O( sizeof(boost::function) * N ) problem, given that
- boost::function object are member data, so allocated on the stack
Hum. I'have used vectors of boost::function objects. Those are definitely not allocated on the stack, and when you have many of them, size starts to matter, and for many signatures the size difference is significant. I do not think this usage is exceptional, in fact boost::signals does exactly that as it keeps a list of boost::functions as callback. I intend to use MSF as a replacement for boost::function, and I will definitely use vectors of MSF.
- boost::function object are created at MSF instantation (seldom event or not in critical loop context?), not during assignment (more often event, more performance critical ? )
Copyng N boost::function objects will require N indirect function calls instead of one for the straight forward implementation. Probably it is not likely to be a bottleneck, but I would not like to pay for what I do not use. The implementation seems needlessly complex :) Also, the extra complexity in the implementation might (or might not) have an effect on compile time.
I would like to know if
- boost::function default c'tor does some allocation? An empty boost::function is cheap to create ?
You can assume so.
- When a functor is assigned by reference with boost::ref boost::function just copies a pointer/reference ?
Since boost-1.34, It should no longer require dynamic memory allocation (due to small object optimization), but that is not guaranteed. Also there will be hard for the compiler to optimize away all the indirect function calls required to copy the stored object. In general a non empty boost::function construction and copy imply a memory allocation.
If the above it's true, but I am not an expert of boost::function, the problem of allocation of N boost::function perhaps is more theoretical then real, also the size problem, given that boost::function requires just 3 pointers does not seem a biggie IMHO.
Well. You can implement msf with just two pointers: one to the virtual table (which is per signature set and not per instance) and one to the actual (heap allocated functor). I think that boost::function has space for an extra pointer so that bound member functions can benefit from SOO, thus sizeof(boost::function) is (usually) sizeof(void*)*3. Your implementation uses at least sizeof(void*) * 3 * N, where N is the number of signatures. In addition I think it requirs an extra pointer to point to the function object. This is very, very wasteful: if you have a vector of msf even of moderate size, the multiplier might be the difference between fitting and not fitting in the cache. Larger stack might also be a problem for threaded programming. In addition you have to consider the N indirect calls you have to do for each copy, comparision etc...
BTW remember the resul_of implementation request? [...] It is very simple, I even don't believe it can work...but it does :-)
Great! :) -- gpd

On Mon, May 12, 2008 at 1:39 PM, Giovanni Piero Deretta <gpderetta@gmail.com> wrote:
On Sat, May 10, 2008 at 7:39 PM, Marco Costalba <mcostalba@gmail.com> wrote:
On Sat, May 10, 2008 at 6:08 PM, Giovanni Piero Deretta wrote:
Marco Costalba <mcostalba@gmail.com> wrote:
Where boost.function naturally models a function, multi-signature boost::function naturally models an overload set
I think this is a great explanation of your function object, Marco, and you should keep this focus. I would encourage you to consider seriously making this purpose explicit by renaming/refactoring your function object into something along the lines of overload_set - give it a name and interface that describes what the function object does (stores and dispatches callable objects based on call signatures similarly to the compiler's "overload set" for a function) rather than naming it according to how it does it (by maintaining multiple boost::functions). This is an interesting and potentially very useful utility by itself - a call-wrapper for multiple callable objects; a cross between a call-wrapper and container, really. <snip>
* A monomorphic function object is a function object which has a single type for each argument (if any) and a single result type. Think for example of the standard (C++03) binders. In practice the argument types are not strictly fixed, as conversions are allowed, or even are fully templated (for example boost::bind). The important part is that the result type is fixed.
<snip>
* A polymorphic function object is a functor which works for multiple argument types, and for which the return value type is (meta)function of the argument types.
That's a good comparison/explanation of poly- vs mono-morphic function objects. By this definition, Marco's multi-signature function is already polymorphic. Well, it is now that it supports result_of, which I thought it already did, but I must have misread something in another thread.
To let client code deduce the result type you should implement the result_of protocol.
// a stateless polymorphic function object: struct twice { template<class Sig> struct result;
// the result type is simply the argument type, but in principle it can be an // arbitrary function of the argument type. template<class T> struct result<twice(T)> { typedef T type; };
template<class T> T operator()(T f) { return f + f; } };
std::cout << twice()(10); // print 20 std::cout << twice()(std::string("hello")); // print "hellohello"
You can (meta)compute the result type of a polymorphic function object using boost::result_of:
boost::result_of<twice(int)>::type i; // i is an int boost::result_of<twice(std::string)>::type j ;// j is a string.
i = twice()(10); j = twice()(std::string("hello");
This seems normal to me. But I don't see the point of your next step, Giovanni.
Now, what if I want to erase the actual type of the function object? If I use boost::function I have to fix the argument type:
boost::function<int(int)>f1= twice();
f1(10); // ok, returns 20 f1(10.7); // bad, returns 20 again! f2(std::string("hello")); // doesn't even compile!
which means that the function object is no longer polymorphic. Well, i can pass an int to f1 and it will (kind of) work, but it will certainly no longer work for std::string.
twice() is already polymorphic. If you want to use it polymorphically, you don't need to do any additional work. Why wrap it in the first place?
That's where a multisignature function object would help:
boost::msf_function<double(double), int(int), std::string(std::string)> f2 = twice(); // magic here!
f2(10); // ok: 20 f2(10.7); // ok: 21.4 f2(std::string("hello")); // great: "hellohello"
How does that help? You could just have written: twice f2; // no need for magic here! f2(10); // ok: 20 f2(10.7); // ok: 21.4 f2(std::string("hello")); // great: "hellohello" I don't see the point of wrapping twice().
I.e. MSF is the natural extension of boost::function in the realm of polymorphic function objects (well, you still have to choose beforehand the types you want to work with, but it is still much better than boost::function).
If you have to choose the types beforehand, then I'm not sure that this extension is so natural. I mean, I see what you're getting at - there is a need for a function object (call it polymorphic_function, for example) whose operator() would be templated. But I don't think this multi-signature function should be coerced into that function object. They're not the same thing. As I understand it, the point of boost::function is that it can defer/hold arbitrary callable objects; i.e. it promotes second-class builtins to first-class. For consistency, it also holds function objects, though there's no other point to it since function objects are already first-class and already deferred. It would be nice to have a call-wrapper, like polymorphic_function, that would do the same thing as boost::function (promote builtins, single interface for builtins and functors, etc.) but without "fixing" the types of polymorphic function objects. For example, with boost::function we can write: template<class T0, class T1> T0 call(function<T0(T1)> f, T1 t1) { return f(t1); } int g(int) { return 0; } struct h { int operator()(int) { return 0; } }; function<int(int)> f0 = g; function<int(int)> f1 = h(); call(f0, 0); call(f1, 0); With polymorphic_function we could write: template<class Magic> typename result_of< polymorphic_function<Magic>(int)
::type call(polymorphic_function<Magic> f) { return f(0); }
g0(g<int>, g<float>);
int g(int) { return 0; } struct h { template<class T> T operator()(T) { return 0; } }; polymorphic_function<Magic> f0 = g; polymorphic_function<Magic> f1 = h(); call(f0); call(f1); In other words, by some Magic, the types of the parameters at the call site do not need to be known when polymorphic_function defers/wraps a callable object. However, no matter how powerful the Magic, the following is not possible. template<class T> T g(T t) { return t; } // assigning an unresolved function polymorphic_function<Magic> f0 = g; // error call(f0); This is because the overload set generated by the function template g() has no type. Actually, an overload can't even be generated without knowing the types at the call site. You cannot promote a builtin function template to first-class and completely preserve the original's polymorphism. However, in some use-cases, we can get around this problem with something like a boost::overload_set that wraps multiple callable objects and can be used to approximate a "deferral" of the compiler's overload resolution. This is where the multi-signature function could help. template<class T> T g(T t) { return t; } overload_set< mpl::vector<int(int), float(float)>) polymorphic_function<Magic> f0 = g0; call(f0); I have some ideas about the Magic involved with polymorphic_function, but I'll save that for another thread. My point is just that Marco's multi-signature function is a solution to one problem but not both. <snip>
Currently your interface does not support directly binding a polymorphic function object to all signatures, but as you shown, it can be done easily.
I know this conversation has progressed elsewhere in this thread, and I'm not completely caught up. I think that binding multiple signatures to a single function object by default, without the user explicitly requesting it, may not be a good thing. My initial preference is to allow ref() for these situations, as Marco has suggested, but I'll reserve judgement until I can better see where y'all are going with it. Daniel Walker

AMDG Daniel Walker wrote:
I think that binding multiple signatures to a single function object by default, without the user explicitly requesting it, may not be a good thing. My initial preference is to allow ref() for these situations, as Marco has suggested, but I'll reserve judgement until I can better see where y'all are going with it.
I suspect that there are really two tools here. One which allows separate function objects to be bound to each signature, more like a fusion sequence or something. The other binds all overloads to a single object. Neither one is easily implementable in terms of the other. If all the signatures are bound at once, then it is difficult to later change just one. If the functions are bound separately, then there is a significant size overhead compared to using a single object. In Christ, Steven Watanabe

On Wed, May 14, 2008 at 7:01 AM, Steven Watanabe <watanabesj@gmail.com> wrote:
AMDG
Daniel Walker wrote:
I think that binding multiple signatures to a single function object by default, without the user explicitly requesting it, may not be a good thing. My initial preference is to allow ref() for these situations, as Marco has suggested, but I'll reserve judgement until I can better see where y'all are going with it.
I suspect that there are really two tools here. One which allows separate function objects to be bound to each signature, more like a fusion sequence or something. The other binds all overloads to a single object. Neither one is easily implementable in terms of the other. If all the signatures are bound at once, then it is difficult to later change just one. If the functions are bound separately, then there is a significant size overhead compared to using a single object.
Great point Steven. Yes, my proposal would not let one rebind signatures separately (not easily at least). If this is an useful thing (really, I do not know), then please Marco, disregard most of my comments, probably I'm really looking for something else. -- gpd

On Wed, May 14, 2008 at 10:31 AM, Giovanni Piero Deretta <gpderetta@gmail.com> wrote:
On Wed, May 14, 2008 at 7:01 AM, Steven Watanabe <watanabesj@gmail.com> wrote:
AMDG
I suspect that there are really two tools here. One which allows separate function objects to be bound to each signature, more like a fusion sequence or something. The other binds all overloads to a single object. Neither one is easily implementable in terms of the other. If all the signatures are bound at once, then it is difficult to later change just one. If the functions are bound separately, then there is a significant size overhead compared to using a single object.
Great point Steven.
Yes, my proposal would not let one rebind signatures separately (not easily at least). If this is an useful thing (really, I do not know), then please Marco, disregard most of my comments, probably I'm really looking for something else.
--
Yes. I fully agree with Steven and with you. But because I have already implemented both features (indeed also a third one, see below for passing a boost::ref(poly_obj) ) I propose to do the following: - Rename proposed set_all() in set_polymorphic_object() The point here is not to set all the msf slots, but to assign a poly oject to a msf, that's the goal, the fact that doing this the slots become all occupied is a side effect. So let the API reflect this. Also IMHO would be misleading using operator=() in this case because assigning a poly object opens the door to a whole set (currently 3) of different behaviours that are not present in the other cases so let the API reflect this. - Default to rebind signatures separately as suggested by Daniel and seconded by Giovanni. The point here is that the "natural" extension is doing this and the other behaviour is the sub-optimal one as pointed out by Steven and Giovanni due to size overhead and possibly not intuitive behaviour as suggested by Daniel - Allow the bind to a single copy of poly objects as requested by Giovanni: The point is that this feature as been requested ;-) and is possible to implement it easily although with sub-optimal size. The user API for this will be a boolean argument defaulted to false in set_polymorphic_object() - Allow to call set_polymorphic_object( boost::ref(poly_obj) ) The point here is completeness of solution because boost::function can do this and because there are cases in which I want to modify a poly_object state externally from MSF while poly_obj is still bounded. I think the 3 different handling of poly objects cover this case at least as long as msf is considered just a boost::function extension, as I would be glad to stick with. The case of interest for Giovanni is implemented in a performance point of view sub-optimal way but it works and anyway the _real_ (read benchmarked) performance penalty is still not very clear to me IMHO. Comments? Thanks Marco

On Wed, May 14, 2008 at 7:22 AM, Marco Costalba <mcostalba@gmail.com> wrote:
On Wed, May 14, 2008 at 10:31 AM, Giovanni Piero Deretta <gpderetta@gmail.com> wrote:
On Wed, May 14, 2008 at 7:01 AM, Steven Watanabe <watanabesj@gmail.com> wrote:
AMDG
I suspect that there are really two tools here. One which allows separate function objects to be bound to each signature, more like a fusion sequence or something. The other binds all overloads to a single object. Neither one is easily implementable in terms of the other. If all the signatures are bound at once, then it is difficult to later change just one. If the functions are bound separately, then there is a significant size overhead compared to using a single object.
Great point Steven.
Yes, my proposal would not let one rebind signatures separately (not easily at least). If this is an useful thing (really, I do not know), then please Marco, disregard most of my comments, probably I'm really looking for something else.
--
Yes. I fully agree with Steven and with you. But because I have already implemented both features (indeed also a third one, see below for passing a boost::ref(poly_obj) ) I propose to do the following:
Not to be overly concerned with the aesthetic appeal of the function object, but the fact that you already did the work is not a good reason to include it in the library. That's not to say that your work will go to waste, but that it shouldn't be exposed so directly to the user. Sometimes what you leave out is as important as what you put in. I would rather have a clean, orderly, even spartan interface than one that supports ever imaginable feature. Here's a good saying: do one thing well and then be extendable. If your function behaved more container-like, or as Steve suggested, like a fusion sequence, then each signature slot would hold its own callable object, but you could do something like the following to bind all the signatures to a single object as Giovanni requested. overload_set<mpl::vector<int(int), float(float)> > functions; fill(begin(functions), end(functions), ref(my_polymorphic_functor)) This is similar to what you are already doing with assign() or set_all() or set_polymorphic_object(). I'm just saying that instead of adding yet another member function, look for a more primitive, fundamental interface. For example, add support for intrinsics like begin() and end() that would let you do the same thing using external algorithms as the member function would have done internally. If there are efficiencies to be gained by having access to your internal implementation, overload the algorithm (as a friend, for example) to take advantage of your implementation. The point is the user has no learning curve and your library becomes more flexible/generic; the user employs your collection of functions interchangeably with other collections of things and they all behave as expected. Your multi-signature function is not merely an extension of boost::function; it is a container of callable objects. Why not make it act like one?! ;-) Daniel Walker

On Wed, May 14, 2008 at 5:05 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
Your multi-signature function is not merely an extension of boost::function; it is a container of callable objects. Why not make it act like one?! ;-)
Daniel, I have to say that I agree with you 100% on the design goals you present. In particular I'm a huge fan of keep it simple and do one thing and do it well. Also the argument of let MSF be orthogonal to standard algorithms is very sound. What I'm asking myself is that if, in its current form, MSF can be taught as a container. As example you wrote this overload_set<mpl::vector<int(int), float(float)> > functions; fill(begin(functions), end(functions), ref(my_polymorphic_functor)) But begin(), end() and fill() need a forward iterator concept to work. In it's current form, if I have to do the analogy with a container I would say that MSF is more similar to an hash then, say, a vector or a list. It's a kind of hash with the key being a function signature: you throw in a signature and get the underlying object. There is no concept of order or position of an overload against another at least "in its current form". I would need to throw in a good chunk of metaprogramming infrastructure to get compile time constants for indices and a bunch of metastuff to handle them. At the end probably it would be another thing. Also in the two examples that I wrote in documentation (a dynamic dispatcher and an object factory) MSF is used as a value, as a container item, of a std::map in the first case and of a tuple in the second case. Also the examples of Govanni, for what I have understood, treat MSF more has a value or a function object then a container. Of course you are 100% right when you say that MSF could be a container, but IMHO it depends a lot on the use. I explain myself better. When dealing with MSF I tend to recognize two phases or two steps (I'm not native speaker so please forgive me if I do not choose the correct words). First step is to load the gun: Define a MSF object and assign to it the functions/functors Second step is to shot: Use one or many of these MSF object to make the job done (call stuff, dynamic dispatch, handle containers of MSF items and so on) I would say that I see more MSF as a container in the first step, and as an item (of another container) in the second step. Anyway this is very hand waving and probably fundamentally silly. So, just to be concrete, I've pushed to boost Vault the file msf-1.1.zip with the new stuff that arise from these very good discussions. In particular there is the result_of support and the "controversial" ;-) set_polymorphic_object() code. I have updated tutorial.html and test.cpp to reflect this. One word regarding the API: it is EXPERIMENTAL. Reading this thread I found a lot of good arguments to change the current function names, unfortunately not all suggestion went in a single direction. So I more or less left the API as it was, but I understand a lot of names, starting from "multi-signature function" itself, are simple placeholders for the future better ones as soon as we agree on what they are :-) Thanks for your precious feedback and help, response of all of you has been overhelming, above my best expectations. Thanks Marco

On Wed, May 14, 2008 at 2:34 PM, Marco Costalba <mcostalba@gmail.com> wrote:
On Wed, May 14, 2008 at 5:05 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote: <snip> But begin(), end() and fill() need a forward iterator concept to work. In it's current form, if I have to do the analogy with a container I would say that MSF is more similar to an hash then, say, a vector or a list.
Well, it's kind of an associative container - associating a signature with a callable object. But you should pick whichever concepts you feel are best suited and would like to support and then implement them. And again Fusion's concepts may actually be a better starting point than the STL, since each function object could have a different type. It may take some work, but it would be worth it. <snip>
First step is to load the gun: Define a MSF object and assign to it the functions/functors
Second step is to shot: Use one or many of these MSF object to make the job done (call stuff, dynamic dispatch, handle containers of MSF items and so on)
Great analogy! For shooting the gun you should model function object concepts - either SGI STL or Fusion or something new if necessary. With operator() and result_of support you already have about everything a person could ask for, so this part is basically done. However, shooting the gun is useless unless it's loaded, and your current infrastructure for loading the gun is lacking. I would suggest modeling some container concept for this or Fusion's sequences or something like them. Incidentally, would you be interested in contributing this as part of a larger library for functional programming in C++? I feel like there could be synergy here with Shunsuke's Egg library. Perhaps, if the three (or more) of us put our heads together we could come up with something new and helpful that we could submit to Boost together. Daniel Walker

On Wed, May 14, 2008 at 6:33 AM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
On Mon, May 12, 2008 at 1:39 PM, Giovanni Piero Deretta
<gpderetta@gmail.com> wrote:
On Sat, May 10, 2008 at 7:39 PM, Marco Costalba <mcostalba@gmail.com> wrote:
On Sat, May 10, 2008 at 6:08 PM, Giovanni Piero Deretta wrote:
Marco Costalba <mcostalba@gmail.com> wrote:
<snip> <more snip>
* A monomorphic function object is a function object which has a single type for each argument (if any) and a single result type. Think for example of the standard (C++03) binders. In practice the argument types are not strictly fixed, as conversions are allowed, or even are fully templated (for example boost::bind). The important part is that the result type is fixed.
<snip>
* A polymorphic function object is a functor which works for multiple argument types, and for which the return value type is (meta)function of the argument types.
That's a good comparison/explanation of poly- vs mono-morphic function objects. By this definition, Marco's multi-signature function is already polymorphic.
Sure it is. Marco wanted a clear explanation and not knowing from where to start, I start from the beginning :)
[ some stuff which show twice being polymorphic]
This seems normal to me. But I don't see the point of your next step, Giovanni.
Now, what if I want to erase the actual type of the function object? If I use boost::function I have to fix the argument type:
boost::function<int(int)>f1= twice();
f1(10); // ok, returns 20 f1(10.7); // bad, returns 20 again! f2(std::string("hello")); // doesn't even compile!
which means that the function object is no longer polymorphic. Well, i can pass an int to f1 and it will (kind of) work, but it will certainly no longer work for std::string.
twice() is already polymorphic. If you want to use it polymorphically, you don't need to do any additional work. Why wrap it in the first place?
That was just an example. No need to make it polymorphic in that case, I can directly use twice. But often you need to erase the type (because you want a type homogeneous collection of functors, because you want to do runtime dispatching or many more reasons) . I wasn't showing why I would want do it. I was just showing what behavior I would like, if I have to do it.
That's where a multisignature function object would help:
boost::msf_function<double(double), int(int), std::string(std::string)> f2 = twice(); // magic here!
f2(10); // ok: 20 f2(10.7); // ok: 21.4 f2(std::string("hello")); // great: "hellohello"
How does that help? You could just have written:
twice f2; // no need for magic here!
my statement "That's where a multisignature function object would help" was missing the "assuming that I need to erase the type of a polymorphic function object". If I can use twice directly fine, I'll do it, is faster and easier. But when you can't, you just can't :)
I.e. MSF is the natural extension of boost::function in the realm of polymorphic function objects (well, you still have to choose beforehand the types you want to work with, but it is still much better than boost::function).
If you have to choose the types beforehand, then I'm not sure that this extension is so natural.
Without some sort of template virtual functions, I do not think we can do better. With extensive type registration you can sort of approximate it.
I mean, I see what you're getting at - there is a need for a function object (call it polymorphic_function, for example) whose operator() would be templated. But I don't think this multi-signature function should be coerced into that function object. They're not the same thing.
IMHO they are. At least a multi signature function should be the most reasonable approximation of a fully polymorphic function object with type erasure. Renaming it to overload_set, as you proposed, might shift the focus on multiple signatures of the same underlying function object to a collection of multiple objects, but honestly, I do not think I have ever had a need for the latter.
As I understand it, the point of boost::function is that it can defer/hold arbitrary callable objects; i.e. it promotes second-class builtins to first-class. For consistency, it also holds function objects, though there's no other point to it since function objects are already first-class and already deferred.
Yep, exactly :). Their primary reason is to wrap function objects and let them "boldly go where no template has gone before".
It would be nice to have a call-wrapper, like polymorphic_function, that would do the same thing as boost::function (promote builtins, single interface for builtins and functors, etc.) but without "fixing" the types of polymorphic function objects. For example, with boost::function we can write:
template<class T0, class T1> T0 call(function<T0(T1)> f, T1 t1) { return f(t1); }
Well, if I need to make 'call' templated on the signature set, I might as well make 'call' templated on the whole function type. The only reason I can think that you might want to do that is to cut down template instantiations (you need to instantiate a 'call' for each signature instead of one for each function object type).
int g(int) { return 0; }
struct h { int operator()(int) { return 0; } };
function<int(int)> f0 = g; function<int(int)> f1 = h();
call(f0, 0); call(f1, 0);
With polymorphic_function we could write:
template<class Magic> typename result_of< polymorphic_function<Magic>(int)
::type call(polymorphic_function<Magic> f) { return f(0); }
int g(int) { return 0; }
struct h { template<class T> T operator()(T) { return 0; } };
polymorphic_function<Magic> f0 = g; polymorphic_function<Magic> f1 = h();
call(f0); call(f1);
In other words, by some Magic, the types of the parameters at the call site do not need to be known when polymorphic_function defers/wraps a callable object. However, no matter how powerful the Magic, the following is not possible.
template<class T> T g(T t) { return t; }
// assigning an unresolved function polymorphic_function<Magic> f0 = g; // error
call(f0);
This is because the overload set generated by the function template g() has no type. Actually, an overload can't even be generated without knowing the types at the call site. You cannot promote a builtin function template to first-class and completely preserve the original's polymorphism.
I think that the important point is that it doesn't really matter what types the function object support, but it is a matter of what types the caller will pass to the function object; The implementor of a function which takes a polymorphic callback knows the types it will pass to the callback, so it can easily encode them in its signature. typedef boost::tuple<int, double, float> my_tuple ; // defined in another translation unit for_each(my_tuple&, boost::msf<void(int&), void(double&), void(float&)>); struct printer { template<class T> void operator()(T x) { std::cout << x; } }; my_type t = ...; for_each(t, printer()); Printer in principle works with all OutputStreamable types, but we do not need to encode this in the interface to for_each. for_each only needs its callback to work with the set of elements in the tuple.
However, in some use-cases, we can get around this problem with something like a boost::overload_set that wraps multiple callable objects and can be used to approximate a "deferral" of the compiler's overload resolution. This is where the multi-signature function could help.
template<class T> T g(T t) { return t; }
g0(g<int>, g<float>);
overload_set< mpl::vector<int(int), float(float)>) polymorphic_function<Magic> f0 = g0;
call(f0);
I have some ideas about the Magic involved with polymorphic_function, but I'll save that for another thread. My point is just that Marco's multi-signature function is a solution to one problem but not both.
Agree, see also my reply to Steven. About the Magic in poly_function, I'm having some thoughts about hijacking BOOST_TYPEOF type registration machinery or postprocessing linker errors... I'll have to think about it.
<snip>
Currently your interface does not support directly binding a polymorphic function object to all signatures, but as you shown, it can be done easily.
I know this conversation has progressed elsewhere in this thread, and I'm not completely caught up. I think that binding multiple signatures to a single function object by default, without the user explicitly requesting it, may not be a good thing. My initial preference is to allow ref() for these situations, as Marco has suggested, but I'll reserve judgement until I can better see where y'all are going with it.
Marco has shown that ref (plus some magic to store a copy of my functor in MSF) is a solution for my problem, but IMHO with an inacceptable overhead compared with the straightforward solution. There might be space in boost for different wrappers which implement each behavior. If it is deemed useful, It is probably better if Marco's MSF maintains its current behavior. -- gpd

On Wed, May 14, 2008 at 5:50 AM, Giovanni Piero Deretta wrote:
On Wed, May 14, 2008 at 6:33 AM, Daniel Walker wrote:
As I understand it, the point of boost::function is that it can defer/hold arbitrary callable objects; i.e. it promotes second-class builtins to first-class. For consistency, it also holds function objects, though there's no other point to it since function objects are already first-class and already deferred.
Yep, exactly :). Their primary reason is to wrap function objects and let them "boldly go where no template has gone before".
I love that - "boldly go!" But just to be perfectly clear and to make sure everyone's on the same page, when I said arbitrary callable objects I meant any object f for which expressions like f() are well formed; i.e. function references and function pointers in addition to function objects. So, the primary reason is to wrap arbitrary callable objects into function objects; i.e. to promote second class builtin functions to first class. The light came on for me after reading 20.5.15.2 and 20.5.1 in N2588. <snip>
template<class T> T g(T t) { return t; }
g0(g<int>, g<float>);
overload_set< mpl::vector<int(int), float(float)> polymorphic_function<Magic> f0 = g0;
call(f0);
I have some ideas about the Magic involved with polymorphic_function, but I'll save that for another thread. My point is just that Marco's multi-signature function is a solution to one problem but not both.
Agree, see also my reply to Steven.
About the Magic in poly_function, I'm having some thoughts about hijacking BOOST_TYPEOF type registration machinery or postprocessing linker errors... I'll have to think about it.
Actually, just for polymorphic_function, what I have in mind is much simpler. It's so simple it doesn't really deserve to be called magic; it's more of a mere technique. Nonetheless, I sometimes think it's nothing less than the grace of God that I arrived at it at all! I was going to discuss this in response to some comments Shunsuke made in his Egg review (and I still plan on responding!), but since it came up again, I'll just tell the whole story here. First, Giovanni, I really do like your definition of polymorphic function objects, but for a moment let's consider polymorphism from a more abstract level. A more general definition of polymorphism could be two types representing the same thing. For some polymorphic types conversion is implicit, and for others, users are required to explicitly convert objects from one type to another. For example, take the relationship between the string "0" and the integer 0. These are two types that both refer to the same number - zero. In some languages, these types can be used completely interchangeably, but in C++ we have lexical_cast. Now, in a similar way, given a polymorphic version of std::plus, for example... struct plus { template <class> struct result; template <class T> struct result<plus(T,T)> { typedef T type; }; template<class T> T operator()(T t0, T t1) { return t0 + t1; } }; function<int(int,int)> add_ints = plus(); function<float(float,float)> add_floats = plus(); ... add_ints and add_floats are objects of two different types that both refer to the same function - plus. To convert between them, what is needed is a functional_cast. Now, boost::function already has infrastructure to support this via its target() member function. However, it does not retain the underlying polymorphic functor type. We need some protocol to encode/communicate this type. It seems to me that result_of's signature template argument already does just what we need! As a matter of explanation, call signatures, as I understand them, come from C and are of the form: return_type(first_argument_type, second_argument_type) These are the sorts of signatures that boost::function must be instantiated with. However, by convention, result_of uses the return_type position of a call signature to store the type of a callable object, which could be a polymorphic function object. Let's call this protocol a "polymorphic" signature. Comparing the two, in call signatures the return type position denotes the return type of a function; in "polymorphic" signatures the return type position denotes the type of a potentially polymorphic callable object. Giovanni, note that this corresponds nicely to your definition of polymorphic function objects as having variable return types. So, the "polymorphic" signatures used by result_of are of the form function_type(first_argument_type, second_argument_type) By using "polymorphic" signatures as the target of the cast, implementing functional_cast is trivial and allows you to do conversions like so: function<int(int,int)> f0 = functional_cast<plus(int,int)>(add_floats); function<float(float,float)> f1 = functional_cast<plus(float,float)>(add_ints); With this notion of two different signature protocols - boost::functions's call signature and result_of's "polymorphic" signature - implementing polymorphic_function can be reduced to the problem of writing a call-wrapper that supports both signature protocols and dispatches to the appropriate cast. Actually, it's even simpler than that. Since the call wrapper for polymorphic function objects will have access to the actual type of the wrapped object via the "polymorphic" signature, there's no need to cast anything. functional_cast is only needed to recover from boost::function's type erasure. polymorphic_function doesn't erase the wrapped type specified in the "polymorphic" signature and can therefore dispatch to the wrapped function object directly. However, result_of's "polymorphic" signature protocol does not yet encode all the information need to wrap a polymorphic function object. For example, what should the signature be for the following functor? struct f { template <class> struct result; template <class T> struct result<f(T,int)> { typedef T type; }; template<class T> T operator()(T t, int i); }; How do you specify that the first argument corresponds to a template parameter while the second argument is an int? As a solution, I think using MPL placeholders is adequate. So the fully polymorphic signature for the function object above would be f(_1,int). In other words, Magic = f(_1,int). ;-) Now polymorphic_function can be used in place of boost::function to wrap arbitrary callable objects without compromising polymorphism. // A function. int f(int i) { return i; } // A polymorphic functor. struct g { template <class> struct result; template <class T> struct result<g(T)> { typedef T type; }; template<class T> T operator()(T t) { return t; } }; // Treat call signatures the same as boost::function polymorphic_function<int(int)> f0 = f; polymorphic_function<int(int)> f1 = g(); // Treat polymorphic signatures polymorphically polymorphic_function<g(_1)> f2 = g(); I've attached a file that provides a simple unary implementation of all this as a proof of concept and to give an idea of what the boilerplate would look like. It should work for both C++03 and 0x. I tested with gcc 4.3. If there's interest, maybe this and Marco's work and possible parts of Egg could be organized into something really useful. Daniel Walker

On Thu, May 15, 2008 at 3:06 AM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
I've attached a file that provides a simple unary implementation of all this as a proof of concept and to give an idea of what the boilerplate would look like. It should work for both C++03 and 0x. I tested with gcc 4.3. If there's interest, maybe this and Marco's work and possible parts of Egg could be organized into something really useful.
Hi Daniel, thanks a lot definitely there is interest, I will take a deep look at Egg (that I don't know) and also to your polymorphic_function<> On this I have a naive question, just to clear the things for me. The point of Giovanni is to use a generalized callback for type erasure of underlying function, but when you write function<int(int,int)> f0 = functional_cast<plus(int,int)>(add_floats); function<float(float,float)> f1 = functional_cast<plus(float,float)>(add_ints); The fact that the poly class is "plus" it's explicit anyway. IOW what's the difference of the above from function<int(int,int)> f0 = plus(); function<float(float,float)> f1 = plus(); Again, in other words, does functional cast support this ? struct g { template <class> struct result; template <class T> struct result<g(T)> { typedef T type; }; template<class T> T operator()(T t) { return t; } int internal_state; g() : internal_state(0) {} }; function<float(float,float)> add_floats = plus(); add_floats.internal_state = 7; function<int(int,int)> add_ints = plus(); std::cout << add_ints.internal_state; // it's 0 of course function<int(int,int)> f0 = functional_cast<plus(int,int)>(add_floats); std::cout << f0.internal_state; // if it's 7 then you have made something very very interesting Thanks Marco

On Thu, May 15, 2008 at 2:07 AM, Marco Costalba <mcostalba@gmail.com> wrote:
On Thu, May 15, 2008 at 3:06 AM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
I've attached a file that provides a simple unary implementation of all this as a proof of concept and to give an idea of what the boilerplate would look like. It should work for both C++03 and 0x. I tested with gcc 4.3. If there's interest, maybe this and Marco's work and possible parts of Egg could be organized into something really useful.
Hi Daniel,
thanks a lot definitely there is interest, I will take a deep look at Egg (that I don't know) and also to your polymorphic_function<>
Cool!
On this I have a naive question, just to clear the things for me.
The point of Giovanni is to use a generalized callback for type erasure of underlying function, but when you write
function<int(int,int)> f0 = functional_cast<plus(int,int)>(add_floats); function<float(float,float)> f1 = functional_cast<plus(float,float)>(add_ints);
The fact that the poly class is "plus" it's explicit anyway. IOW what's the difference of the above from
function<int(int,int)> f0 = plus(); function<float(float,float)> f1 = plus();
The assignments to f0 or f1 using functional_cast wraps a copy of the original plus object wrapped by add_floats or add_ints. The second assignments wrap brand new plus objects.
Again, in other words, does functional cast support this ?
<snip>
std::cout << f0.internal_state; // if it's 7 then you have made something very very interesting
Yes, so long as the copy constructor of the wrapped function object maintains internal_state. Alternatively, I believe you could use ref() and the wrapped object would always be the same, not a copy. Also, to access the members of the wrapped object you need to use boost::function::target() like so: std::cout << f0.target<plus>()->internal_state; functional_cast uses function::target() internally. This API is in the C++0x standard as well, so functional_cast can work with both boost::function and std::function; they're more or less the same anyway. Daniel Walker

On Thu, May 15, 2008 at 8:36 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
Yes, so long as the copy constructor of the wrapped function object maintains internal_state.
If the copy c'tor copies the internal state then what's the difference between: function<float(float,float)> add_floats = plus(); add_floats.target<plus>()->internal_state = 7; function<int(int,int)> f0 = functional_cast<plus(int,int)>(add_floats); std::cout << f0.internal_state; // it's 7 ! And function<float(float,float)> add_floats = plus(); add_floats.target<plus>()->internal_state = 7; plus tmp( *add_floats.target<plus>() ); // copy c'tor here ! function<int(int,int)> f0 = tmp; std::cout << f0.target<plus>()->internal_state; // should be 7 the same I would say It seems that expression function<int(int,int)> f0 = functional_cast<plus(int,int)>(add_floats); is very similar to plus tmp( *add_floats.target<plus>() ); function<int(int,int)> f0 = tmp; Is this correct ? Thanks Marco

On Thu, May 15, 2008 at 5:59 PM, Marco Costalba <mcostalba@gmail.com> wrote:
On Thu, May 15, 2008 at 8:36 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
Yes, so long as the copy constructor of the wrapped function object maintains internal_state.
If the copy c'tor copies the internal state then what's the difference between:
function<float(float,float)> add_floats = plus();
add_floats.target<plus>()->internal_state = 7;
function<int(int,int)> f0 = functional_cast<plus(int,int)>(add_floats);
std::cout << f0.internal_state; // it's 7 !
And
function<float(float,float)> add_floats = plus();
add_floats.target<plus>()->internal_state = 7;
plus tmp( *add_floats.target<plus>() ); // copy c'tor here !
function<int(int,int)> f0 = tmp;
std::cout << f0.target<plus>()->internal_state; // should be 7 the same
I would say It seems that expression
function<int(int,int)> f0 = functional_cast<plus(int,int)>(add_floats);
is very similar to
plus tmp( *add_floats.target<plus>() );
function<int(int,int)> f0 = tmp;
Is this correct ?
Yes, that's basically all there is to it. Really, it's just .... function<int(int,int)> f0 = *add_floats.target<plus>(); ... with error checking. functional_cast is almost as simple as lexical_cast. They're both just syntactic sugar in a way. They communicate the notion that you're converting between two types that represent the same thing. Check out the implementation I sent yesterday. functional_cast's body is just four lines. It's nothing fancy; it's just more expressive and possibly more convenient than directly manipulating pointers to boost::function's innards. Daniel

On Thu, May 15, 2008 at 11:37 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
Yes, that's basically all there is to it. Really, it's just ....
function<int(int,int)> f0 = *add_floats.target<plus>();
... with error checking.
functional_cast is almost as simple as lexical_cast. They're both just syntactic sugar in a way. They communicate the notion that you're converting between two types that represent the same thing. Check out the implementation I sent yesterday. functional_cast's body is just four lines. It's nothing fancy; it's just more expressive and possibly more convenient than directly manipulating pointers to boost::function's innards.
I've checked out now. I didn't wanted to look before because I wanted to try to understand myself, it helps in my understanding when reading the actual code ;-)...that I have to say is very nice. I've learnt a lot of tricks from that few lines. One thing. Regarding the actual core // Cast between two boost::functions with different call signatures // wrapping the same polymorphic function object. template<class Signature, class CallSignature> function<typename call_signature<signature<Signature> >::type> functional_cast(function<CallSignature> f) { typedef typename callable_object<Signature>::type functor_type; functor_type const* p = f.template target<functor_type>(); if(!p) throw std::bad_cast(); return function<typename call_signature<signature<Signature> >::type>(*p); } I would say that for it to be equivalent to function<int(int,int)> f0 = *add_floats.target<plus>(); It may be return function<typename call_signature<signature<Signature>
::type>(boost::ref(*p));
instead of return function<typename call_signature<signature<Signature> >::type>(*p); because boost::function makes a copy as default, so you have one copy of *p in the boost::function c'tor in the return type and another, outside functional_cast in the assignment function<int(int,int)> f0 = functional_cast<...>(..); Marco

On Fri, May 16, 2008 at 1:36 AM, Marco Costalba <mcostalba@gmail.com> wrote:
On Thu, May 15, 2008 at 11:37 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote: I would say that for it to be equivalent to
function<int(int,int)> f0 = *add_floats.target<plus>();
It may be
return function<typename call_signature<signature<Signature>
::type>(boost::ref(*p));
instead of
return function<typename call_signature<signature<Signature> >::type>(*p);
because boost::function makes a copy as default, so you have one copy of *p in the boost::function c'tor in the return type and another, outside functional_cast in the assignment
function<int(int,int)> f0 = functional_cast<...>(..);
Excellent point. Thanks! However, you don't need (and you don't necessarily want...) the reference_wrapper when returning the new function. Actually, the return statement can be reduced to return *p, since the new boost::function in the return type is constructable from *p. Doh! ;-) This still doesn't take care of boost::function's continuous copying of the wrapped function object. However, as you know, boost::function handles reference_wrapped function objects to allow users to eliminate this overhead. So, functional_cast should also handle reference_wrapped function objects. Unfortunately, result_of does not handle reference_wrapped function objects! The workaround is simple (by the way, this is largely due to Tobias Schwinger function_types library... so thanks!), though it would also be simple to add reference_wrapped function object support to result_of. If there's interests I can add a feature request to Track and submit a patch. Anyway, the modifications I made in response to your comments are below. This can still be improved upon. For instance, the constness of the original reference_wrapper is not propagated correctly, but this suffices as a proof of concept. Daniel Walker --- polymorphic_function.cpp~ 2008-05-16 12:17:13.795000000 -0400 +++ polymorphic_function.cpp 2008-05-16 12:53:10.892000000 -0400 @@ -8,6 +8,7 @@ #include <boost/function_types/components.hpp> #include <boost/function_types/function_type.hpp> #include <boost/function_types/result_type.hpp> +#include <boost/mpl/at.hpp> #include <boost/mpl/identity.hpp> #include <boost/mpl/placeholders.hpp> #include <boost/mpl/pop_front.hpp> @@ -16,6 +17,23 @@ using namespace boost; +template<class Signature> +struct workaround_result_of_reference_wrapper_issue { + typedef typename function_types::function_type< + typename mpl::push_front< + mpl::pop_front< + function_types::components<Signature> + > + , typename unwrap_reference< + typename mpl::at< + function_types::components<Signature> + , mpl::int_<0> + >::type + >::type + > + >::type type; +}; + // A wrapper for a "polymorphic" signature, which has no fixed return // type but instead uses the return type position of builtin call // signatures to specify the type of a potentially polymorphic @@ -43,7 +61,11 @@ mpl::pop_front< function_types::components<Signature> > - , typename result_of<Signature>::type + , typename result_of< + typename workaround_result_of_reference_wrapper_issue< + Signature + >::type + >::type > > { }; @@ -67,10 +89,11 @@ function<typename call_signature<signature<Signature> >::type> functional_cast(function<CallSignature> f) { - typedef typename callable_object<Signature>::type functor_type; - functor_type const* p = f.template target<functor_type>(); + typedef typename callable_object<Signature>::type callable_object_type; + typedef typename unwrap_reference<callable_object_type>::type functor_type; + functor_type * p = f.template target<functor_type>(); if(!p) throw std::bad_cast(); - return function<typename call_signature<signature<Signature> >::type>(*p); + return is_reference_wrapper<callable_object_type>::value ? ref(*p) : *p; } @@ -145,6 +168,17 @@ assert(f1(1)/2 == .5); } + // Cast while respecting reference_wrapper. + { + g f; + function<int(int)> f0 = ref(f); + function<float(float)> f1 + = functional_cast<reference_wrapper<g>(float)>(f0); + + assert(f0(1)/2 == 0); + assert(f1(1)/2 == .5); + } + // Polymorphic function behaves like boost::function when // instantiated with a call signature and is polymorphic with a // "polymorphic" signature.

On Thu, May 15, 2008 at 4:06 AM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
On Wed, May 14, 2008 at 5:50 AM, Giovanni Piero Deretta wrote:
On Wed, May 14, 2008 at 6:33 AM, Daniel Walker wrote:
As I understand it, the point of boost::function is that it can defer/hold arbitrary callable objects; i.e. it promotes second-class builtins to first-class. For consistency, it also holds function objects, though there's no other point to it since function objects are already first-class and already deferred.
Yep, exactly :). Their primary reason is to wrap function objects and let them "boldly go where no template has gone before".
I love that - "boldly go!" But just to be perfectly clear and to make sure everyone's on the same page, when I said arbitrary callable objects I meant any object f for which expressions like f() are well formed; i.e. function references and function pointers in addition to function objects. So, the primary reason is to wrap arbitrary callable objects into function objects; i.e. to promote second class builtin functions to first class. The light came on for me after reading 20.5.15.2 and 20.5.1 in N2588.
Hum, but aren't function pointers already first class? I think that std::function supports them only for completeness. Its main reason is to wrap stateful) function objects (i.e. closures). I'll read N2588 again... yes, it says explicitly in 20.5.15.2.1 that "The function class template [...] [allows] functions to be first class objects". Maybe the distinction is between function and pointer-to-function. Anyways, it is really a detail.
<snip>
template<class T> T g(T t) { return t; }
g0(g<int>, g<float>);
overload_set< mpl::vector<int(int), float(float)> polymorphic_function<Magic> f0 = g0;
call(f0);
I have some ideas about the Magic involved with polymorphic_function, but I'll save that for another thread. My point is just that Marco's multi-signature function is a solution to one problem but not both.
Agree, see also my reply to Steven.
About the Magic in poly_function, I'm having some thoughts about hijacking BOOST_TYPEOF type registration machinery or postprocessing linker errors... I'll have to think about it.
Actually, just for polymorphic_function, what I have in mind is much simpler. It's so simple it doesn't really deserve to be called magic;
Please ignore my comment above, I wasn't (and still I'm not) sure what I was thinking of.
it's more of a mere technique. Nonetheless, I sometimes think it's nothing less than the grace of God that I arrived at it at all! I was going to discuss this in response to some comments Shunsuke made in his Egg review (and I still plan on responding!), but since it came up again, I'll just tell the whole story here.
First, Giovanni, I really do like your definition of polymorphic function objects, but for a moment let's consider polymorphism from a more abstract level. A more general definition of polymorphism could be two types representing the same thing.
where 'thing' is a common interface, I guess. (i.e., a concept in parametric polymorphism or an actual pure base class in subtype polymorphism). So, ok, I agree with this.
For some polymorphic types conversion is implicit, and for others, users are required to explicitly convert objects from one type to another. For example, take the relationship between the string "0" and the integer 0. These are two types that both refer to the same number - zero. In some languages, these types can be used completely interchangeably, but in C++ we have lexical_cast.
I'm not sure if explicit conversion count: you lose the ability to treat different types in the same way. Of course you can add another level of indirection, by making also the conversion function a parameter and itself parametric: // generic indirection layer template<typename To, template<class,class> Convert, typename From> To operation_that_requires_a_generic_type_conversion(From f) { return Convert<From,To>(f); }
Now, in a similar way, given a polymorphic version of std::plus, for example...
struct plus { template <class> struct result; template <class T> struct result<plus(T,T)> { typedef T type; }; template<class T> T operator()(T t0, T t1) { return t0 + t1; } };
function<int(int,int)> add_ints = plus(); function<float(float,float)> add_floats = plus();
<interlude may_skip=if-you-prefer> I'm a lowly engineer, and know nothing about type theory, but by reading the wikipedia article about Type Polymorphism, I thik you can call this a form of Rank-1 (Prenex) polymorphism: "In a prenex polymorphic system, type variables may not be instantiated with polymorphic types" I.e. you loose the ability to be polymorphic when you actually construct a variable of a polymorphic type, as you have to fix the type. If c++ didn't allow creating variables of type 'plus' and only allowed variables of type function<sig>, it would have a Rank-1 Polymorphic Type system. A variable of type 'plus' is instead 'Rank-n' polymorphic, I.e. it retains its polymorphic behavior no matter how many levels of nesting are applyed (i.e. you can pass it to an higher order function which in turn is passed to an higher order function and so on). Wikpedia definition doesn't make it clear: "Rank-n polymorphism is polymorphism in which quantifiers may appear to the left of arbitrarily many arrows." but FC++ authors explicitly says that C++ polymorphic function objects (from now on PFO) are Rank-n polymorphic and I'll believe them :). The problem is of course that to maintain the polymorphic behavior of a C++ PFO, you have to use them in a template context (i.e. all higher order functions must be templated). It would be interesting to know if constrained templates (i.e. ConceptCPP allows Rank-n polymorphism, but I'm not sure: you have to specify in the concept requirement of an higher order function the signature of the passed function object, but the fact that you can define it in term of other template arguments might be an escape hatch: in fact I think that as long as everything is explicitly typed, that is, no type inference, there isn't much distinction between all rank of polymorphism) </interlude> ok, I'm still following you :)
... add_ints and add_floats are objects of two different types that both refer to the same function - plus. To convert between them, what is needed is a functional_cast.
Now, boost::function already has infrastructure to support this via its target() member function. However, it does not retain the underlying polymorphic functor type. We need some protocol to encode/communicate this type.
I think this is in direct contrast with the primary reason of std::function (or any other type erasure wrapper), which is to erase the type of the wrapped function and only retain its behavior. I do not see how you can retain the type and still preserve it...
It seems to me that result_of's signature template argument already does just what we need!
As a matter of explanation, call signatures, as I understand them, come from C and are of the form:
return_type(first_argument_type, second_argument_type)
These are the sorts of signatures that boost::function must be instantiated with.
ok.
However, by convention, result_of uses the return_type position of a call signature to store the type of a callable object, which could be a polymorphic function object. Let's call this protocol a "polymorphic" signature.
In a PFO, the result type is (meta) function of the argument types. Thus in result_of, the type in the result position, in a sense, denotes (indirectly) the metafunction to be used to compute the result value. So yes, I'm still with you (even if I do not think that this is the reasoning done by the authors of result_of: it is a kind of ret-connecting).
Comparing the two, in call signatures the return type position denotes the return type of a function; in "polymorphic" signatures the return type position denotes the type of a potentially polymorphic callable object. Giovanni, note that this corresponds nicely to your definition of polymorphic function objects as having variable return types.
Well, this is not exactly what I meant: a PFO does not necessarily have a variable return type nor this is its principal charateristics. This is a detail though, let's move on.
So, the "polymorphic" signatures used by result_of are of the form
function_type(first_argument_type, second_argument_type)
By using "polymorphic" signatures as the target of the cast, implementing functional_cast is trivial and allows you to do conversions like so:
function<int(int,int)> f0 = functional_cast<plus(int,int)>(add_floats); function<float(float,float)> f1 = functional_cast<plus(float,float)>(add_ints);
Ok, but you need to know the function type (i.e. plus). So, what is the point of using std::function then? Note that in many cases where std::function is useful (for example to hold the result of a complex lambda or bind expression), you do not know the stored function type.
With this notion of two different signature protocols - boost::functions's call signature and result_of's "polymorphic" signature - implementing polymorphic_function can be reduced to the problem of writing a call-wrapper that supports both signature protocols and dispatches to the appropriate cast.
Actually, it's even simpler than that. Since the call wrapper for polymorphic function objects will have access to the actual type of the wrapped object via the "polymorphic" signature, there's no need to cast anything. functional_cast is only needed to recover from boost::function's type erasure. polymorphic_function doesn't erase the wrapped type specified in the "polymorphic" signature and can therefore dispatch to the wrapped function object directly.
However, result_of's "polymorphic" signature protocol does not yet encode all the information need to wrap a polymorphic function object. For example, what should the signature be for the following functor?
struct f { template <class> struct result; template <class T> struct result<f(T,int)> { typedef T type; }; template<class T> T operator()(T t, int i); };
How do you specify that the first argument corresponds to a template parameter while the second argument is an int? As a solution, I think using MPL placeholders is adequate. So the fully polymorphic signature for the function object above would be f(_1,int).
In other words, Magic = f(_1,int). ;-)
Now polymorphic_function can be used in place of boost::function to wrap arbitrary callable objects without compromising polymorphism.
// A function. int f(int i) { return i; }
// A polymorphic functor. struct g { template <class> struct result; template <class T> struct result<g(T)> { typedef T type; }; template<class T> T operator()(T t) { return t; } };
// Treat call signatures the same as boost::function polymorphic_function<int(int)> f0 = f; polymorphic_function<int(int)> f1 = g();
// Treat polymorphic signatures polymorphically polymorphic_function<g(_1)> f2 = g();
this of course works, but you are no longer erasing the type of g here!!! It is right there, encoded in polymorphic_function instantiation: I cannot use it to pass a PFO to a function in another translation unit, I cannot use it to store a lambda function because I do not know its type and I cannot build a type homogeneous container which stores wrappers to different PFOs! What is the point of using a wrapper then? I do not think that there is a (non contrived) use case where a non erasing polymorphic_function object is more useful than using 'g' directly. function_cast might have some limited usability, but I cannot see when I would use your variant of polymorphic_function. Am I missing something? -- gpd

On Thu, May 15, 2008 at 9:09 AM, Giovanni Piero Deretta <gpderetta@gmail.com> wrote:
On Thu, May 15, 2008 at 4:06 AM, Daniel Walker
I.e. you loose the ability to be polymorphic when you actually construct a variable of a polymorphic type, as you have to fix the type. If c++ didn't allow creating variables of type 'plus' and only allowed variables of type function<sig>, it would have a Rank-1 Polymorphic Type system.
A variable of type 'plus' is instead 'Rank-n' polymorphic, I.e. it retains its polymorphic behavior no matter how many levels of nesting are applyed (i.e. you can pass it to an higher order function which in turn is passed to an higher order function and so on). Wikpedia definition doesn't make it clear:
I haven't read the Wiki you're citing, and this is my first exposure to some of this terminology, but this seems like a good categorization to me. However, I would say that C++ supports multiple polymorphic types. function<sig> is rank-1 polymorphic, where as 'plus' is rank-n. Another example, std::plus is rank-1, and the 'plus' from my example is rank-n. Thanks for bringing this up; these seem like really useful distinctions.
... add_ints and add_floats are objects of two different types that both refer to the same function - plus. To convert between them, what is needed is a functional_cast.
Now, boost::function already has infrastructure to support this via its target() member function. However, it does not retain the underlying polymorphic functor type. We need some protocol to encode/communicate this type.
I think this is in direct contrast with the primary reason of std::function (or any other type erasure wrapper), which is to erase the type of the wrapped function and only retain its behavior. I do not see how you can retain the type and still preserve it...
See, I think the primary utility of boost::function is that it allows you to treat builtin functions and function objects more interchangeable. You can assign either a function pointer or a function object to a boost::function object as long as they have the same call signature. It blurs the boundary between second and first class functions. I think the type erasure of wrapped function objects is a by product of the fact that builtin functions have no type, at least not in the sense of constructability; i.e. there are no values in C++ that are of a function type. Maybe our different view points stem from the notion of wrapping. boost::function is a call-wrapper, which is to say it's purpose is to deffer a function call (i.e. implement operator() to dispatch to a previously specified function). In doing so, boost::function also erases the type of the contained callable objects, and can be viewed as a "type-wrapper." polymorphic_function is a call-wrapper, which allows the user to specify whether or not to erase the type of contained function objects.
By using "polymorphic" signatures as the target of the cast, implementing functional_cast is trivial and allows you to do conversions like so:
function<int(int,int)> f0 = functional_cast<plus(int,int)>(add_floats); function<float(float,float)> f1 = functional_cast<plus(float,float)>(add_ints);
Ok, but you need to know the function type (i.e. plus). So, what is the point of using std::function then?
The point is to treat arbitrary callable objects as first class; i.e. using function you can guarantee that whether you're given a builtin function or function object you will be able to work with first class types and first class values. Now in a situation where you have more information, and you know that the rank-1 polymorphic boost::function is wrapping a rank-n polymorphic object, functional_cast allows you to cast between each of the n "ranks" of the rank-n function object. Or something to that effect. ;-)
Note that in many cases where std::function is useful (for example to hold the result of a complex lambda or bind expression), you do not know the stored function type.
That's true. If you don't know the polymorphic type, you cannot use it polymorphically. This has always been the case with boost::function, and there's no change from the status quo here.
Now polymorphic_function can be used in place of boost::function to wrap arbitrary callable objects without compromising polymorphism.
// A function. int f(int i) { return i; }
// A polymorphic functor. struct g { template <class> struct result; template <class T> struct result<g(T)> { typedef T type; }; template<class T> T operator()(T t) { return t; } };
// Treat call signatures the same as boost::function polymorphic_function<int(int)> f0 = f; polymorphic_function<int(int)> f1 = g();
// Treat polymorphic signatures polymorphically polymorphic_function<g(_1)> f2 = g();
this of course works, but you are no longer erasing the type of g here!!! It is right there, encoded in polymorphic_function instantiation: I cannot use it to pass a PFO to a function in another translation unit, I cannot use it to store a lambda function because I do not know its type and I cannot build a type homogeneous container which stores wrappers to different PFOs!
You can use polymorphic_function (maybe it should be called rankn_function) the same way as boost::function. So, if you want to erase the type, instantiate it with a call signature the same as boost::function. Then you can use it across translation units, store lambda functions in it, all that. But if you have a polymorphic object, and you'd like to maintain it's polymorphism, you have to tell the compiler its type (so that it can preform overload resolution on the operator()s at the call site). boost::function doesn't allow you to make this trade-off. polymorphic_function allows you to select between the two - rank-1 or rank-n, to continue to use the proper terminology - by specifying either call signatures or polymorphic signatures.
What is the point of using a wrapper then? I do not think that there is a (non contrived) use case where a non erasing polymorphic_function object is more useful than using 'g' directly.
The point is to have a uniform way of treating functions as first class, both builtins and function objects. polymorphic_function handles all the same use cases as boost::function plus an additional one. boost::function decouples a function call from the values at the call site, but not the types, so it can only support rank-1 polymorphism. polymorphic_function also decouples the types at the call site, when wrapping an object that can support rank-n polymorphism. Here's a concrete example that hopefully isn't too contrived, and also goes back to the topic of this thread. The multi-signature function must be loaded with at least one signature that exactly matches the types at the call site (well, convertibly matches). If none exist, there's an error. What if you wanted a fall-back overload? For example, say you're making an overload_set to preform addition, and you have a special, custom function for integers as well as my polymorphic plus example from before. The polymorphic plus could serve as a fallback for adding types other than int, but with an overload_set implementation based on boost::function, the best you can do is "demote" plus to numerous rank-1 objects. int add_ints(int x, int y) { // do something special return x + y; } overload_set< mpl::vector< int(int,int) , float(float,float) , complex(complex,complex) // .etc >
add(add_ints , plus , plus // and so on );
If the overload_set were instead based on polymorphic_function, then after loading add_int for integers, you only need to specify plus once to handle all other types. overload_set< mpl::vector<int(int,int), plus(_1,_1)>
add(add_ints, plus);
This is possible because polymorphic_function provides a single interface to wrap both builtins and function objects as rank-1 or rank-n accordingly. Granted the magic is all in the "polymorphic" signature. But polymorphic_function conveniently provides a single interface for handling both signature protocols. Great points! Thanks! Daniel Walker

On Fri, May 16, 2008 at 12:25 AM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
If the overload_set were instead based on polymorphic_function, then after loading add_int for integers, you only need to specify plus once to handle all other types.
overload_set< mpl::vector<int(int,int), plus(_1,_1)>
add(add_ints, plus);
This is fundamentally different

On Fri, May 16, 2008 at 12:45 PM, Marco Costalba <mcostalba@gmail.com> wrote:
On Fri, May 16, 2008 at 12:25 AM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
If the overload_set were instead based on polymorphic_function, then after loading add_int for integers, you only need to specify plus once to handle all other types.
overload_set< mpl::vector<int(int,int), plus(_1,_1)>
add(add_ints, plus);
This is fundamentally different from writing overload_set< mpl::vector<"comma separated function signatures">
add(add_ints, plus)
In the latter case you instantiate plus for each signature in the overload_set (or multi signature function MSF, if you prefer). In your example you pass typename T where T = plus as template parameter. mpl::vector<int(int,int), plus(_1,_1)> Is no more a vector of signatures, it'a a vector of signatures + a class type. It is a vector of heterogeneous item types. This is _really_ totally different also from an implementation point of view. Indeed a MSF boils down to a hierarchy of operator=() each one defined on a given signature and each one forwarding to a corresponding boost::function What you suggest is to have a fall back MSF defined as: template<typename Signatures, class fall_back_poly_class> class function : public fall_back_poly_class { ......good old multi sig. function implementation ..... } In other words MSF _derives_ from poly class so that when a call matches some operator=() signature the normal path is choosen, when a call does not mach compiler synthetizes a new operator=() from the poly base class. Indeed Signatures can be more flexible of poly because poly is arity constrained, as example plus takes _only_ two arguments. While signatures list can contain signatures of any and also different arity. A simple generalization to overcome this could be: template<typename signatures_sequence, typename poly_sequence> class fallback_function : public "derive vertically from all the poly objects in poly_sequence" { ......good old multi sig. function implementation ..... } Is my interpretation correct? If it is and you are interested in such an object I think I can tweak multi-signature function to handle that. Thanks Marco

On Fri, May 16, 2008 at 7:10 AM, Marco Costalba <mcostalba@gmail.com> wrote:
On Fri, May 16, 2008 at 12:45 PM, Marco Costalba <mcostalba@gmail.com> wrote:
On Fri, May 16, 2008 at 12:25 AM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
If the overload_set were instead based on polymorphic_function, then after loading add_int for integers, you only need to specify plus once to handle all other types.
overload_set< mpl::vector<int(int,int), plus(_1,_1)>
add(add_ints, plus);
This is fundamentally different from writing
overload_set< mpl::vector<"comma separated function signatures">
add(add_ints, plus)
In the latter case you instantiate plus for each signature in the overload_set (or multi signature function MSF, if you prefer).
I'm not convinced of what's the best name for this, but I am convinced that multi_signature_function::function is definitely not a good name. I think it could cause confusion with std::function, and though they're both call-wrappers, this notion of aggregating callable objects and then dispatching them based on their signatures is significantly different from boost/std::function. It does something very similar to what the compiler does internally with an overload set, which is why I think it's fairly natural and more descriptive to somehow use the term "overload." I noticed you even implement it in a file called overload.hpp; I think that's the right direction to move in.
In your example you pass typename T where T = plus as template parameter.
mpl::vector<int(int,int), plus(_1,_1)>
Is no more a vector of signatures, it'a a vector of signatures + a class type. It is a vector of heterogeneous item types.
Nope. Try: typedef mpl::vector<int(int,int), plus(_1, _1)> signature_types; BOOST_MPL_ASSERT(( is_function< mpl::at_c<signature_types, 1>::type > )); It's still a vector of signatures. There are two kinds of signature here (by convention or protocol): * int(int, int) is the usual C/C++ call signature * plus(_1,_1) is our new emerging polymorphic signature by convention The polymorphic signature uses the same syntax as the native call signature but with different semantics. The type prior to the parens denotes a callable object or reference_wrapped callable object. The types inside the parens denote template parameters if they are MPL placeholders, or they denote argument types otherwise. When the type prior to the parens (let's call this the object position of the expression) is a (possibly reference_wrapped) rank-n polymorphic function object, the call-wrapper exhibits rank-n polymorphism. As an aside, I prefer the term "functor" to "function object," since we're talking about a type not an object, but the SGI STL concepts used the term "function object" - I think it's also in the standard and Boost.Fusion. Also, I just realized I made a revealing mistake in nomenclature while changing functional_cast to support reference_wrappers. The change was: - typedef typename callable_object<Signature>::type functor_type; + typedef typename callable_object<Signature>::type callable_object_type; + typedef typename unwrap_reference<callable_object_type>::type functor_type; callable_object simply returns whatever is in the object position of the Signature. However, when that object is a reference_wrapper it isn't actually a callable object, so that's not a good name. (This is exactly why result_of doesn't handle reference_wrapped function objects - reference_wrapper is not a callable object.) To help clarify things, I think it would be useful to further formalize this signature protocol with a set of type traits similar to boost::function_types. For example: object_type<Signature> // same as as function_types::return_type callable_object_type<Signature> // the actual unreference_wrapped callable object is_template_parameter<Signature, 0> // true for MPL placeholders ... and perhaps most importantly ... is_polymorphic_function<Signature> // to distinguish from is_functon<>
This is _really_ totally different also from an implementation point of view. Indeed a MSF boils down to a hierarchy of operator=() each one defined on a given signature and each one forwarding to a corresponding boost::function
I started looking more closely at your implementation, and I like the way you do the class hierarchy. But the important part here is the hierarchy of operator()s right? You could do assignment to the various signature slots with an insert() or at() rather than operator=, right? I mean you could do it in theory, if you refractored your implementation accordingly.
What you suggest is to have a fall back MSF defined as:
template<typename Signatures, class fall_back_poly_class> class function : public fall_back_poly_class { ......good old multi sig. function implementation ..... }
<snip>
Is my interpretation correct?
No, I think this is incorrect due to the false assumption that plus(_1,_1) is not a signature. From briefly looking at your implementation, I think the simplest way to implement this would be to replace the internal boost::function with polymorphic_function and add a function_caller that isn't partially specialized on the decomposed signature. This general function_caller would dispatch rank-n polymorphic calls. This won't compile yet, but the change I'm think of (starting from the msf_27_4_2008.zip version) would be something like ... --- overload.hpp~ 2008-05-16 15:38:42.035000000 -0400 +++ overload.hpp 2008-05-16 15:55:33.261000000 -0400 @@ -37,7 +37,7 @@ template <typename Base, typename Sig> struct function_holder : Base { - typedef boost::function<Sig> boost_fun_type; + typedef polymorphic_function<Sig> boost_fun_type; boost_fun_type boost_fun; @@ -163,6 +163,25 @@ namespace boost { namespace multi_signature_function { namespace detail { + template <typename Base, typename Sig> + struct function_caller : function_holder<Base, Sig> + { + typename boost::result_of<boost_fun_type()>::type + operator()() { return this->boost_fun(); } + + template <typename A0> + typename boost::result_of<boost_fun_type(A0)>::type + operator()(A0 a0) { return this->boost_fun(a0); } + + template <typename A0, typename A1> + typename boost::result_of<boost_fun_type(A0,A1)>::type + operator()(A0 a0, A1 a1) { return this->boost_fun(a0, a1); } + + template <typename A0, typename A1, typename A2> + typename boost::result_of<boost_fun_type(A0,A1,A2)>::type + operator()(A0 a0, A1 a1, A2 a2) { return this->boost_fun(a0, a1, a2); } + }; + /* Start of argument arity dependant part * * Define one function_caller specialization each signature arity to I'm sure there's more to it, but that gives you an idea. Of course, the first thing you need is an nary version of polymorphic_function. If you're serious about this and that's the direction you'd like to go in, I'd be glad to start working on it tomorrow! Daniel Walker

On Fri, May 16, 2008 at 9:03 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
It's still a vector of signatures. There are two kinds of signature here (by convention or protocol):
* int(int, int) is the usual C/C++ call signature * plus(_1,_1) is our new emerging polymorphic signature by convention
Ok, now I understand, thanks, but still there is a fundamental difference between int(int, int) and plus(_1,_1), namely the first it's just an interface but the latter does real work, actually adds stuff. I try to explain myself better with an example starting from the normal functions case: int add(int a, int b) { return a + b; } int sub(int a, int b) { return a - b; } bool is_positive(int a) { return a > 0; } bool is_negative(int a) { return a < 0; } msf::function<mpl::vector<int(int, int), bool(int)> > f(add, is_positive); assert( f(3, 2) == 5); assert( f(6) == true ); f = sub; f = is_negative; assert ( f(3, 2) == 1 ); assert( f(6) == false ); Ok. Simple. Now extend to polymorphic case: struct add { template<class T> T operator()(T a, T b) { return a + b; } }; struct minus { template<class T> T operator()(T a, T b) { return a - b; } }; struct is_positive { template<class T> bool operator()(T a) { return a > 0; } }; struct is_negative { template<class T> bool operator()(T a) { return a < 0; } }; Now what I would expect for this generalization is: msf::function<mpl::vector<_1(_1, _1), bool(_1)> > f(plus, is_positive); assert( f(3, 2) == 5); assert( f(3.5, 2.5) == 6.0); assert( f(6) == true ); assert( f(6.7) == true ); f = minus; f = is_negative; assert ( f(3, 2) == 1 ); assert ( f(3.5, 2.5) == 1 ); assert( f(6) == false ); assert( f(6.7) == false ); So here we have: msf::function<mpl::vector<_1(_1, _1), bool(_1)> > not msf::function<mpl::vector<plus(_1, _1), is_positive(_1)> > because the vector of function signatures define the interface that function should have to be wrapped by the overload set, as you prefer to call it ;-), so also in polymorphic case the vector should keep "polymorphic signatures" that different polymorphic classes with the proper polymorphic signature should match to be _wrapped_ by the overload set, not to be the underlying function, replacing boost::function as you suggested. In this case boost::function should be replaced by a wrapper of polymorphic functors, not by _a_ polymorphic functor defined in mpl::vector at msf::function instantiation. Am I missing something? BTW I don't even figure up how this wrapper of poly objects looks like ! or if it even exist.
This is _really_ totally different also from an implementation point of view. Indeed a MSF boils down to a hierarchy of operator=() each one defined on a given signature and each one forwarding to a corresponding boost::function
I started looking more closely at your implementation, and I like the way you do the class hierarchy. But the important part here is the hierarchy of operator()s right?
Yes. I meant that. It was a silly typo, I meant " a hierarchy of operator()"
This won't compile yet, but the change I'm think of (starting from the msf_27_4_2008.zip version) would be something like
This is very old, now is out msf-1.1.zip and in few hours it will be out msf-1.2.zip with the improved interface for poly objects, namely the remove of set_polymorphic_object() and use of operator=() instead. I suggest to download one of the above because they are very different from the version you have.
I'm sure there's more to it, but that gives you an idea. Of course, the first thing you need is an nary version of polymorphic_function. If you're serious about this and that's the direction you'd like to go in, I'd be glad to start working on it tomorrow!
Great!! I'm very interested in polymorphic generalization too, but I would think is difficult stuff, too difficult for me alone ;-) Marco

On Sat, May 17, 2008 at 1:39 AM, Marco Costalba <mcostalba@gmail.com> wrote:
On Fri, May 16, 2008 at 9:03 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
It's still a vector of signatures. There are two kinds of signature here (by convention or protocol):
* int(int, int) is the usual C/C++ call signature * plus(_1,_1) is our new emerging polymorphic signature by convention
Ok, now I understand, thanks, but still there is a fundamental difference between int(int, int) and plus(_1,_1), namely the first it's just an interface but the latter does real work, actually adds stuff.
I try to explain myself better with an example starting from the normal functions case:
<snip>
So here we have:
msf::function<mpl::vector<_1(_1, _1), bool(_1)> >
not
msf::function<mpl::vector<plus(_1, _1), is_positive(_1)> >
because the vector of function signatures define the interface that function should have to be wrapped by the overload set, as you prefer to call it ;-), so also in polymorphic case the vector should keep "polymorphic signatures" that different polymorphic classes with the proper polymorphic signature should match to be _wrapped_ by the overload set, not to be the underlying function, replacing boost::function as you suggested.
In this case boost::function should be replaced by a wrapper of polymorphic functors, not by _a_ polymorphic functor defined in mpl::vector at msf::function instantiation.
Am I missing something?
BTW I don't even figure up how this wrapper of poly objects looks like ! or if it even exist.
This is interesting, but something different. _1(_1,_1) and bool(_1) are not what I meant by polymorphic signature. I haven't thought about how you would do this either or if it's even possible. The definition for a polymorphic signature protocol that I have in mind requires that the first position be a callable object or referenced wrapped callable object. _1 and bool are not callable objects - no operator(). So, for the first position, a polymorphic signature is almost exactly like the signatures passed to result_of. (BTW, this could be enforced by the compiler with a concept check.) For all the following positions in the signature inside parens, they can be either an actual argument type or a placeholder. Placeholders indicate a template parameter in the function's argument list (not an unspecified function object outside the argument list). Actually, come to think of it, _1(_1, _1) would probably not be possible because it doesn't encode the type of a polymorphic function object, so there's no way for the compiler to use that type's set of overloaded operator()s later on at the call site. _1(_1,_1) is type erasure again and that breaks polymorphic function objects.
I'm sure there's more to it, but that gives you an idea. Of course, the first thing you need is an nary version of polymorphic_function. If you're serious about this and that's the direction you'd like to go in, I'd be glad to start working on it tomorrow!
Great!! I'm very interested in polymorphic generalization too, but I would think is difficult stuff, too difficult for me alone ;-)
Well, I ended up taking the weekend off. ;-) But I'll download your latest version and get back with you later this week. This will be fun if nothing else! Daniel Walker

On Mon, May 19, 2008 at 4:26 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
a placeholder. Placeholders indicate a template parameter in the function's argument list (not an unspecified function object outside the argument list). Actually, come to think of it, _1(_1, _1) would probably not be possible because it doesn't encode the type of a polymorphic function object, so there's no way for the compiler to use that type's set of overloaded operator()s later on at the call site. _1(_1,_1) is type erasure again and that breaks polymorphic function objects.
Well, the first _1 is intended to be the return type, not the polymorphic type. It's _1(_1, _1) because plus and minus return T: T plus(T, T), T minus(T, T) So it's bool (T) because is_positive and is_negative return a bool. Actually I think there is no way to create a polymorphic functor wrapper, but anyway it's the logical extension of function signatures in the polymorphic world because function signatures do not imply _any_ algorithm or functionality apart from arguments and return type. So a poly signature should define return type and arguments ONLY. Because here we talk about templates, i.e. family of types and not a single type we can only specify argument arity and when argument types should be the same, as in plus, or different as _3(_1, _2) I would think overload_set is based on the concept of wrapping a function (call it type erasure), but when you assign plus(_1,_1) there is nothing to wrap, just use plus instantiated by compiler according to the calling sites arguments. If you need a generic fallback it is better to let overload_set derive directly from plus() and you have what you need. Comments? Thanks Marco

On Mon, May 19, 2008 at 1:37 PM, Marco Costalba <mcostalba@gmail.com> wrote:
On Mon, May 19, 2008 at 4:26 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
a placeholder. Placeholders indicate a template parameter in the function's argument list (not an unspecified function object outside the argument list). Actually, come to think of it, _1(_1, _1) would probably not be possible because it doesn't encode the type of a polymorphic function object, so there's no way for the compiler to use that type's set of overloaded operator()s later on at the call site. _1(_1,_1) is type erasure again and that breaks polymorphic function objects.
Well, the first _1 is intended to be the return type, not the polymorphic type.
Aha, my bad, I misunderstood you. You intended the first _1 to indicate a variable return type, right? That's not a bad idea, except we already have an expression to indicate that a function has a variable (a.k.a. argument dependent) return type - the signatures of the result_of protocol. The signature protocol I'm defining is identical to the result_of protocol except that it can additionally use MPL placeholders in the argument list to represent template parameters (and it handles reference_wrapped functors).
It's _1(_1, _1) because plus and minus return T: T plus(T, T), T minus(T, T)
So it's bool (T) because is_positive and is_negative return a bool.
Actually I think there is no way to create a polymorphic functor wrapper, but anyway it's the logical extension of function signatures in the polymorphic world because function signatures do not imply _any_ algorithm or functionality apart from arguments and return type.
By extending the protocol used by result_of to include placeholders representing template parameters in the argument list, we can wrap polymorphic functors without loss of polymorphism. The file I sent earlier includes a unary implementation of such a call-wrapper called polymorphic_function.
So a poly signature should define return type and arguments ONLY. Because here we talk about templates, i.e. family of types and not a single type we can only specify argument arity and when argument types should be the same, as in plus, or different as _3(_1, _2)
See, I think it should extend the result_of signature's protocol for encoding variable return types... again, by specifying a callable object type in the first position of the signature. Also of interest, Shunsuke Sogame has an experimental multi-signature call-wrapper that uses a very similar signature protocol complete with placeholders representing template parameters (see the Egg review result thread). So, I think this notion of a polymorphic signature composed of a callable object type and optional MPL placeholders is probably a good way to go.
I would think overload_set is based on the concept of wrapping a function (call it type erasure), but when you assign plus(_1,_1) there is nothing to wrap, just use plus instantiated by compiler according to the calling sites arguments.
If you need a generic fallback it is better to let overload_set derive directly from plus() and you have what you need.
The goal that I have in mind is to achieve call-wrapping (that is call deferral, type-erasure is optional) of both builtin functions and what we could call rank-n polymorphic functors - function objects with overloaded/templated operator(). (The generic fallback is just an example application of such a call-wrapper.) To do these two things, we need two signature protocols: a normal boost::function-style call signature for monomorphic builtins and a result_of-style "polymorphic" signature with placeholders for rank-n functors. So, for example, the problem is not wrapping, deferring, or dispatching plus. The problem is managing both signature protocols so that the same call-wrappers (polymorphic_function and by extension overload_set) are generic enough to handle both pointers to monomorphic builtins and instances of rank-n functors. So, I'm advocating the following division of labor: polymorphic_function manages the two signature protocols and can defer a single callable object. overload_set uses polymorphic_function to defer multiple callable objects. See what I'm getting at? Daniel Walker

On Tue, May 20, 2008 at 1:16 PM, Marco Costalba <mcostalba@gmail.com> wrote:
On Tue, May 20, 2008 at 5:35 AM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
See what I'm getting at?
More or less ;-)
I 'm really eager to see the code you are working on to finally understand without ambiguities.
Sorry for the delay. I just put it on vault. Once I got my hands dirty, I wanted to try to get it right. I think it's pretty close to production grade, now. And yeah, there's nothing like code to resolve ambiguities; working on this helped me clarify my own thinking as well. One thing I realized is that I was probably wrong about the modifications you need in order to enable polymorphic signatures:
<daniel.j.walker@gmail.com> wrote: I think the simplest way to implement this would be to replace the internal boost::function with polymorphic_function and add a function_caller that isn't partially specialized on the decomposed signature. This general function_caller would dispatch rank-n polymorphic calls.
I'm not sure that this is actual true, because like boost::function, each polymorphic_function can only be called by one signature. Each function_caller holds only one call wrapper, right? So, the example I gave where the function_caller overloaded operator() for different arities and forwarded to the same underlying call wrapper isn't correct. I'm not sure what the best way of going about this is, but we have a working version of polymorphic_function to play around with now, which may help. Daniel Walker

On Wed, May 28, 2008 at 5:09 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
On Tue, May 20, 2008 at 1:16 PM, Marco Costalba <mcostalba@gmail.com> wrote:
On Tue, May 20, 2008 at 5:35 AM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
See what I'm getting at?
More or less ;-)
I 'm really eager to see the code you are working on to finally understand without ambiguities.
Sorry for the delay. I just put it on vault.
I'm just back after a week off-line due to my job. This is a great news, I'm going to download right now. More to come... Thanks Marco

On Sat, May 10, 2008 at 10:32 AM, Marco Costalba <mcostalba@gmail.com> wrote:
On Sat, May 10, 2008 at 3:17 AM, Giovanni Piero Deretta <gpderetta@gmail.com> wrote:
1) can you dispatch on the dynamic type of an object? I.e.
struct Base { virtual ~Base() {} };
struct A : Base {}; struct B : Base {};
void foo1(A&); void foo2(B&);
f = foo1; f = foo2;
A a; B b; foo((Base&)a); // calls foo1 foo((Base&)b); // calls foo2
Probably you mean
f((Base&)a); // calls foo1 f((Base&)b); // calls foo2
Anyway no you can't. But because also boost::function can't I fail to see an inconsistency. Indeed
boost::function<int(A&)> f= foo1;
f((Base&)a); // calls foo1 <---- COMPILER ERROR: cannot convert parameter 1 from Base to A&
Ok. I know that boost function can't do it, but I thought that dynamic dispatching would come easier once you had multiple overload dispatching functionality. Thinking of it, it probably needs registering all derived types of Base. Anyways I do not think that MSF should provide this, it was just a whish :)
2) If I have a polymorphic function object, can I store a single instance of this object and specify multiple signatures? i.e.
struct foo_t { template<class T> void(T){...} } foo;
Sorry but the line
struct foo_t { template<class T> void(T){} } foo;
does not compile for me. Probably I'm missing something obvious.
I'll reply to this in another email. -- gpd

Marco Costalba wrote:
Hi all,
this is the first official version of multi-signature boost::function extension (MSF) pushed to Boost Vault under the name msf-1.0.zip
Personally, I always thought getting a function objet per signature was a bad idea. Just take a single one with multiple overloads. Basically what you do with set_polymorphic_object, except you don't store it N times but only once. You may also want to provide a (separate) generic tool to generate a single function object from multiple ones.

On Fri, May 16, 2008 at 5:04 PM, Mathias Gaunard <mathias.gaunard@ens-lyon.org> wrote:
Marco Costalba wrote:
Hi all,
this is the first official version of multi-signature boost::function extension (MSF) pushed to Boost Vault under the name msf-1.0.zip
Personally, I always thought getting a function objet per signature was a bad idea. Just take a single one with multiple overloads. Basically what you do with set_polymorphic_object, except you don't store it N times but only once.
Well, I'm changing again the API (yes I know it's painful, but this time is the last one, I promise). I would like to use operator=() also for polymorphic function objects and deal the single copy issue as presented by Giovanni with a class policy. I explain better with the example stripped from the new test.cpp now just in my private trunk, btw it works! struct poly_t { int call_cnt; poly_t() : call_cnt(0) {} template<class T> T operator()(T t) { call_cnt++; return t; } }; .......strip..... /* In case the assigned object is a polymorphic function object * then all the internal boost::functions are bounded in one go */ poly_t poly_obj; msf::function<boost::mpl::vector<char(char), string(string)> > fp(poly_obj); assert( fp('x') == 'x' ); assert( fp("hello") == "hello" ); assert( fp("hello") == "hello" ); /* By default boost::function makes a copy of the functor, so * we end up with a different copy of poly_obj for each signature * and the variable poly_obj::call_cnt is updated independently * by the two calls. Below we retrieve the object wrapped by * each of the two underlying boost::function and verify that * poly_t::call_cnt is duplicated. */ assert( fp.get<char(char)>().target<poly_t>()->call_cnt == 1 ); assert( fp.get<string(string)>().target<poly_t>()->call_cnt == 2 ); /* In some cases it is expensive (or semantically incorrect) to * clone a polymorphic function object. In such cases, it is possible * to request to keep only a reference to the actual function object. * This is done using the ref() function to wrap a reference to a * polymorphic function object */ poly_t external_poly_obj; fp = boost::ref(external_poly_obj); external_poly_obj('x'); // note that we call this not through fp external_poly_obj("hello"); assert( fp.get<char(char)>().target<poly_t>()->call_cnt == 2 ); assert( fp.get<string(string)>().target<poly_t>()->call_cnt == 2 ); /* A special case is when we need to have only a single copy of the * polymorphic object for all the signatures. In this case we have to * set to poly_single_copy the Tag template parameter of msf::function * that normally defaults to poly_multi_copy */ poly_t* poly_obj_ptr = new poly_t(); msf::function< boost::mpl::vector<char(char), string(string)>, msf::poly_single_copy > fp_si(*poly_obj_ptr); // work both as c'tor argument... fp_si = *poly_obj_ptr; //... and as assignment delete poly_obj_ptr; // delete now, a copy has already been made assert( fp_si('x') == 'x' ); assert( fp_si("hello") == "hello" ); assert( fp_si("hello") == "hello" ); /* Only one poly_t::call_cnt shared across the signature's slots */ assert( fp_si.get<char(char)>().target<poly_t>()->call_cnt == 3 ); assert( fp_si.get<string(string)>().target<poly_t>()->call_cnt == 3 );
You may also want to provide a (separate) generic tool to generate a single function object from multiple ones.
Please could you better explain this point with an example ? thanks ? Thanks Marco
participants (7)
-
Daniel Walker
-
Eric Niebler
-
Giovanni Piero Deretta
-
Marco Costalba
-
Mathias Gaunard
-
Steven Watanabe
-
vicente.botet