Boost logo

Boost :

From: Giovanni Piero Deretta (gpderetta_at_[hidden])
Date: 2008-06-06 21:17:32


On Fri, Jun 6, 2008 at 9:48 PM, Daniel Walker <daniel.j.walker_at_[hidden]> 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

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