Library proposal: functor_pattern

123 views
Skip to first unread message

Rob Meijer

unread,
Jun 8, 2012, 6:50:32 PM6/8/12
to std-pr...@isocpp.org
I would like to submit the following proposal for a simple (non
lambda) operator() and variadic template based functor pattern
library:

functor_pattern -
https://docs.google.com/document/d/10Ja4y8SsOzgh6AQaamHOZB16HK2SThN1P6TrhaWpnow/edit

I've removed duplicate logic and omitted any reference to code
generation and parallel event loops from the original polafunctor
project.

Dave Abrahams

unread,
Jun 8, 2012, 7:00:58 PM6/8/12
to std-pr...@isocpp.org

on Fri Jun 08 2012, Rob Meijer <pibara-AT-gmail.com> wrote:

> I would like to submit the following proposal for a simple (non
> lambda) operator() and variadic template based functor pattern
> library:
>
> functor_pattern -
> https://docs.google.com/document/d/10Ja4y8SsOzgh6AQaamHOZB16HK2SThN1P6TrhaWpnow/edit

Hi Rob,

I don't understand why we'd want this when we have std::function. I
also have no idea what "attenuation patterns that help increase program
robustness by enabling drop-in attenuation on a functor level," from the
"Motivation" section, is supposed to refer to.

If you could clarify those two points in the document, I think it would
be an improvement.

Thanks,

--
Dave Abrahams
BoostPro Computing
http://www.boostpro.com

Nevin Liber

unread,
Jun 8, 2012, 7:03:45 PM6/8/12
to std-pr...@isocpp.org
On 8 June 2012 17:50, Rob Meijer <pib...@gmail.com> wrote:
I would like to submit the following proposal for a simple (non
lambda) operator() and variadic template based functor pattern
library:

functor_pattern -
https://docs.google.com/document/d/10Ja4y8SsOzgh6AQaamHOZB16HK2SThN1P6TrhaWpnow/edit

What is the benefit of this over std::function?  The only thing I've really seen is the multiple inheritance case for multiple callable signatures, but even that doesn't give me a type that can hold anything matching that calling signature.
--
 Nevin ":-)" Liber  <mailto:ne...@eviloverlord.com(847) 691-1404

Rob Meijer

unread,
Jun 9, 2012, 5:12:52 AM6/9/12
to std-pr...@isocpp.org
2012/6/9 Dave Abrahams <da...@boostpro.com>:
I truly don't understand how having std::function is relevant to my
proposal. Are you suggesting such a library should build on
std::function rather than a class hierarchy? If so, could you give
some pointers on how I should set about doing so?

I've just added a 'use case' section to the proposal document that
shows how the proposed library could be used in practice. Hope this
clarifies the main motivation for this library proposal.

Rob Meijer

unread,
Jun 9, 2012, 5:31:47 AM6/9/12
to std-pr...@isocpp.org
2012/6/9 Nevin Liber <ne...@eviloverlord.com>:
> On 8 June 2012 17:50, Rob Meijer <pib...@gmail.com> wrote:
>>
>> I would like to submit the following proposal for a simple (non
>> lambda) operator() and variadic template based functor pattern
>> library:
>>
>> functor_pattern -
>>
>> https://docs.google.com/document/d/10Ja4y8SsOzgh6AQaamHOZB16HK2SThN1P6TrhaWpnow/edit
>
>
> What is the benefit of this over std::function?  The only thing I've really
> seen is the multiple inheritance case for multiple callable signatures, but
> even that doesn't give me a type that can hold anything matching that
> calling signature.

I'm a bit puzzled by your response. When asking about the benefit over
std::function, are you talking of use or implementation? When talking
about usage, there doesn't seem to be any overlap. When talking about
implementation, I can't quite envision dropping the hierarchic
approach in favor of std::function, so any pointers on why and how
would be very much welcome.

The multiple inheritance IMO is an implementation detail for a
specific helper class. The concept of the library is to provide a set
of helper classes for implementing functor based patterns, most
notably patterns that involve attenuation of the authority that a
reference to an unattenuated functor may imply. I hope the 'use case'
section I just added to the document clarifies the intent of the
library proposal.

Alisdair Meredith

unread,
Jun 9, 2012, 7:14:41 AM6/9/12
to std-pr...@isocpp.org
Looking at your usage example, it seems like it should be possible
to achieve the same effect today using a combination of std::function
and various std::bind calls.

It would be helpful if your example highlighted the differences with
this approach, to make it clear what you are able to achieve that
the generic bind/function pattern cannot. I think a compare-and-
contrast approach would be most helpful, because at the moment
I don't see the new capabilities you are offering - which is probably
my failing, but anything you can do to make the distinction clearer
will help!

AlisdairM

Bjorn Reese

unread,
Jun 9, 2012, 8:39:55 AM6/9/12
to std-pr...@isocpp.org
On 2012-06-09 00:50, Rob Meijer wrote:

> functor_pattern -
> https://docs.google.com/document/d/10Ja4y8SsOzgh6AQaamHOZB16HK2SThN1P6TrhaWpnow/edit

Could you elaborate on what you mean by "attenuation patterns" and
"drop-in attentuation"?

Rob Meijer

unread,
Jun 9, 2012, 1:54:18 PM6/9/12
to std-pr...@isocpp.org
2012/6/9 Alisdair Meredith <alis...@me.com>:
Do you mean as implementation of a functor pattern library? Or do you
imply combining std::function and std::bind together make a functor
pattern library unneeded?

If you mean the first, than yes, the library proposal chooses an
implementation path where others may exist, though I do see variadic
templates as a prerequisite for any such library, so adding
std::function and std::bind would seem to make implementation a bit
more involved.

If you are implying std::function and std::bind together make a
functor pattern library unneeded, than I disagree. The library
proposal is mainly about providing relatively simple but highly
reusable building blocks.

> It would be helpful if your example highlighted the differences with
> this approach, to make it clear what you are able to achieve that
> the generic bind/function pattern cannot.  I think a compare-and-
> contrast approach would be most helpful, because at the moment
> I don't see the new capabilities you are offering - which is probably
> my failing, but anything you can do to make the distinction clearer
> will help!

I'm afraid I failed in conveying the 'building block' nature of the proposal.
Its not about new capabilities being offered, its about building blocks and
convenience when composing attenuations for injected dependencies
using functors.
An alternative design using std::function and std::bind would absolute
be an option.
and if anyone shows any benefit to the user from such an approach, it might be a
good idea to go back to the drawing board and write a second proposal
that includes
the implementation consequences of including std::function and/or
std::bind to the mix.
The main goal of the library would however remain providing building
blocks that the
user could apply to conveniently attenuate and inject dependencies
into sub-systems.


> AlisdairM

Rob Meijer

unread,
Jun 9, 2012, 2:14:26 PM6/9/12
to std-pr...@isocpp.org
2012/6/9 Bjorn Reese <bre...@mail1.stofanet.dk>:
What I mean with attenuation patterns basically are simple reusable
design patterns that make it possible to attenuate the authority that
is conveyed by an object reference, and in the case of the proposed
library, by a functor. As an example, a logger functor that allows
logging at multiple levels going from DEBUG upto CRITICAL could be
seen as attenuated if a proxy functor would for example scale down
ERROR and CRITICAL and WARNING down to NOTICE. What I mean with
drop-in in this sense is that:

void log(std::string prefix,int level, std::string message);

void Foo::someMethod(...) {
..
log("hmm",LOG_NOTICE,"Oops");
..
}

from a usage perspective would be drop-in replaceable with something like:

Foo::Foo(.... ,
std::functor_pattern::functor<void,std::string,int,std::string>
&logger):...,log(logger){}

void Foo::someMethod(...) {
..
log("hmm",LOG_NOTICE,"Oops");
..
}

Nevin Liber

unread,
Jun 9, 2012, 2:43:25 PM6/9/12
to std-pr...@isocpp.org
On 9 June 2012 04:31, Rob Meijer <pib...@gmail.com> wrote:
I'm a bit puzzled by your response. When asking about the benefit over
std::function,  are you talking of use or implementation?

Usage.

For instance, if I need a class with one callable signature (for this example, let's use void()), I might write the class as:

struct One
{
    template<typename F>
    explicit One(F&& f) : _f(std::forward<F>(f)) {}

    void operator()() const { return _f(); }
private:
    std::function<void()> _f;
};

Now I can take anything which has the callable signature void(), and can use lambdas or std::bind to massage things which don't quite have that signature into something that does.  This gives me a very loose coupling, which I've found to be a great programming practice.

If I needed run time polymorphism with multiple signatures, I might do my own type erasure, depending on my needs.  But even picking something simple like the following base class:

struct Two
{
    Two(Two const&) = delete;
    Two& operator=(Two const&) = delete;
    virtual ~Two() {}

    virtual void operator()(int) = 0;
    virtual void operator()(std::string const&) = 0;
};

Why is your method superior to that?
-- 

Rob Meijer

unread,
Jun 9, 2012, 3:32:43 PM6/9/12
to std-pr...@isocpp.org
2012/6/9 Nevin Liber <ne...@eviloverlord.com>:
Its not, and I don't believe the difference is much exposed to the
user other than the requirement to declare the functor struct a public
functor. The thing the library proposes is a set of re-usable building
blocks that help attenuate your strucs. The current proposal does
require your struct declares that it implements functor so it can be
used as a constructor argument and member in templates defined in the
library. Basically declaring it for example a public
std::functor_pattern::functor<void> is the price you as a user pay for
allowing the library to define for example a quota based condition
proxy for it with the same interface:

struct One: public std::functor_pattern::functor<void>
{
    template<typename F>
    explicit One(F&& f) : _f(std::forward<F>(f)) {}
    void operator()() const { return _f(); }
private:
    std::function<void()> _f;
};

..
One one; //instantiate your functor
std::functor_pattern::quota tentimesmax(10); //instantiate a quota.
std::functor_pattern::null_sink<void> donothing; //instantiate a do
nothing functor with the same interface.
std::functor_pattern::conditional
attenuatedone(one,donothing,tentimesmax);//Create the attenuation
proxy.
Foo foo(attenuatedone); //Pass the attenuated functor to the
constructor of a sub-system.

..
Foo::Foo( std::functor_pattern::functor<void> one):mOne(one) {}
void Foo::someMethod() {
..
mOne();
..
}

If you are suggesting that it may be possible and/or useful to change
the library proposal APIs so that these declarations may evaporate
from the API, than yes, that might be interesting.
Maybe you could ilustrate based on the above how you would envision a
better API for the library to look like.

Dave Abrahams

unread,
Jun 9, 2012, 5:11:16 PM6/9/12
to std-pr...@isocpp.org

on Sat Jun 09 2012, Rob Meijer <pibara-AT-gmail.com> wrote:

> 2012/6/9 Dave Abrahams <da...@boostpro.com>:
>>
>> on Fri Jun 08 2012, Rob Meijer <pibara-AT-gmail.com> wrote:
>>
>>> I would like to submit the following proposal for a simple (non
>>> lambda) operator() and variadic template based functor pattern
>
>>> library:
>>>
>>> functor_pattern -
>>> https://docs.google.com/document/d/10Ja4y8SsOzgh6AQaamHOZB16HK2SThN1P6TrhaWpnow/edit
>>
>> Hi Rob,
>>
>> I don't understand why we'd want this when we have std::function.  I
>> also have no idea what "attenuation patterns that help increase program
>> robustness by enabling drop-in attenuation on a functor level," from the
>> "Motivation" section, is supposed to refer to.
>>
>> If you could clarify those two points in the document, I think it would
>> be an improvement.
>
> I truly don't understand how having std::function is relevant to my
> proposal. Are you suggesting such a library should build on
> std::function rather than a class hierarchy?

I'm suggesting that your proposal seems to be founded on a base class
for a runtime-polymorphic function object. std::function is a
runtime-polymorphic function object that comes with many advantages over
using a raw base class (e.g. no need to manage memory, value semantics,
ad-hoc polymorphism). Therefore, I can't imagine why we'd want to
standardize a raw base class for runtime-polymorphic function objects.

Richard Smith

unread,
Jun 9, 2012, 7:22:49 PM6/9/12
to std-pr...@isocpp.org
Looking at your individual building blocks, most perform functionality that can be expressed more concisely and clearly using std::bind or lambdas. For instance, either of these seem a lot clearer and simpler than the code in your use case:

auto filteredfoologger =
  std::bind(rawlogger, std::bind(nsfilter, _1), std::bind(foolevels, _2), _3);

auto filteredfoologger2 = [](std::string prefix, int level, std::string message) {
  return rawlogger(nsfilter(prefix), foolevels(level), message);
}

I think there are a couple of things that might have some value in this proposal:

discarded_rval seems to be addressing a (small) hole (converting a functor returning T to a function returning void). This can be done by binding a functor which ignores its argument, but perhaps allowing std::function<void(Ts...)> to hold a functor returning any type would be a better way to handle such use cases.

conditional seems like it could make code a little more concise, although that benefit would be eroded if we get variadic polymorphic lambdas in C++17:
  [](&&...args) { return cond() ? f1(args...) : f2(args...); }
Reply all
Reply to author
Forward
0 new messages