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