Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pros and Cons of implementing functionality as functor [closed]

I'm having a discussion with a colleague about the API of a simple class that has only one public method. I initially went for:

class CalculateSomething
{
public:
  void operator()(const SomeObject &obj) const;

private:
  // ...
}

However, my colleague opposes the use of operator() and wishes to simply name the method 'calculate' for the sake of clarity. Although I don't find that argument convincing, it made me think of the pros and cons.

Advantages operator()

  • The class is lean and has a single well-defined purpose. Once instantiated, it basically acts as a free function.
  • It is a functor and can be easily used as such (e.g. STL algorithms).
  • When using it with range algorithms, the object can be passed directly instead of through a function pointer, which enables the compiler to inline the code. Although not guaranteed, passing it through a function pointer completely inhibits this possibility.

Disadvantages operator()

  • It is less clear what the method does without looking at the class name. (I personally disagree as the class has only one method and its meaning is therefore clear from the class name)
  • Most functors in the STL are expected to be stateless. This I think is the main reason that's holding me back...

I was surprised to see that my search on this didn't bring up much since I would assume that this is quite a common scenario (one class, one responsibility). As such, I'm really interested in hearing what other people think about this.

like image 515
dgrine Avatar asked Feb 09 '16 09:02

dgrine


People also ask

What is the difference between a functor and a function pointer Why might we want to use a functor instead of a function pointer?

A function pointer allows a pointer to a function to be passed as a parameter to another function. Function Objects (Functors) - C++ allows the function call operator() to be overloaded, such that an object instantiated from a class can be "called" like a function.

What is the difference between a function and a functor?

A function assigns to every element of a set X an element of a set Y. A functor assigns to every object of a category C an object of a category D and also assigns to every morphism in C a morphism in D in a way compatible with sources, targets, and composition.

Why do we need functor?

Functors give you more flexibility, at the cost of usually using slightly more memory, at the cost of being more difficult to use correctly, and at the cost of some efficiency.

Is std :: function good?

std::function is the great unifying force of those things introduced by C++11. std::function is much older than lambda functions in C++, it's not just to make them easy to use.


2 Answers

If lambdas are really not an option, Your choice should depend on the scope of work that object undertakes... and of cause your coding conventions or styles. You can decide to be explicit (see Werolik's answer), its a good thing if the method is relatively unfamiliar and requires states, but

Let us take simple use-cases from the standard library...

  • std::hash: This is a function object that does one job, and does it supposedly well, no contest about that
  • so many more... including std::less, and its assortments

One thing you see in common with all these is that they are verbs... In my perspective, if your class is exactly like the snippet you posted, CalculateSomething signifies an action to me, so I can always instantiate it as CalculateSomething()(my_object...).

And like you cited, it comes in very handy in using STL algorithm itself and many other C++ libraries. If you go your colleague's method, you may have to resort to using std::binds and lambdas because you want to 'adapt' an interface.

Example:

class CalculateSomething
{
    public:
         void operator()(const SomeObject &obj) const;
    private:
         // ...
}

class CalculateNothing
{
    public:
         void calculate(const SomeObject &obj) const;
    private:
         // ...
}

An example usage is:

std::for_each(container.begin(), container.end(), CalculateSomething());

against

std::for_each(container.begin(), container.end(), [ c = CalculateNothing()](auto x) { c.calculate(x); });

I think I prefer the former.

like image 96
WhiZTiM Avatar answered Oct 09 '22 12:10

WhiZTiM


Well, here are also mine 5 cents.

First of all, if possible, I'd simply use lambda or free function. Are you sure, you need a class for your needs?

Anyway, assuming that class is required.

  1. I don't like using operator() that much. Maybe with additional comments.
  2. Probably it would be good to rename it to 'SomethingCalculator' - isn't it an object?
  3. Than you can add a method, something like 'DoWork', 'Calculate' or whatever.

This will make it much more explicit.

UPD. All above can be still argued, but what I truly believe in, is that adding enough in-code documentation will make the real difference, independent of the method name.

like image 36
Werolik Avatar answered Oct 09 '22 14:10

Werolik