12

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.

moooeeeep
  • 31,622
  • 22
  • 98
  • 187
dgrine
  • 702
  • 6
  • 15
  • 3
    You should probably add constructor to initialize private member btw. And lambda are mostly equivalent to that. – Jarod42 Feb 09 '16 at 09:57
  • Using a operator that way smells a bit like a `command` pattern with dedicated command classes.. That can have some benefits if the application's overall design is fitted with it. If it's the only object that is following this pattern, then it will be a bit of a struggle to maintain. – Stefan Feb 09 '16 at 10:00
  • @Jarod42 The constructor has no bearing on the question. And lambdas cannot hold state, so I'm not really sure what you intend to say. – dgrine Feb 09 '16 at 10:01
  • @moooeeeep Having read that post, it seems that answers delve into Java specific implementation details (e.g. no free functions in Java). Some touch on C++, and from this, I still don't see any convincing argument with most being 'is equivalent to' type of answers. I'm specifically interested in advantages/disadvantages. Not in 'a class with no state and a single public function is equivalent to a free function in a namespace'. – dgrine Feb 09 '16 at 10:59
  • @OnMyLittleDuck: constructors make the premise inaccurate as you then have operator + constructor public, but indeed, it is just detail. Lambda can have state (with capture), and can even be mutable. but it cannot have getter on this capture (but as you said only one public method, so :) ). – Jarod42 Feb 09 '16 at 10:59
  • @moooeeeep this question is a poor fit for Programmers - it would be quickly voted down and closed over there, see [What is the problem with “Pros and Cons”?](http://meta.programmers.stackexchange.com/q/6758/31260) Recommended reading: **[What goes on Programmers.SE? A guide for Stack Overflow](http://meta.programmers.stackexchange.com/q/7182/31260)** – gnat Feb 09 '16 at 12:31
  • _passing it through a function pointer completely inhibits this possibility._ This has long been untrue. When did you last look at generated assembly? – Maxim Egorushkin Feb 10 '16 at 10:26
  • @MaximEgorushkin Thank you for pointing that out. This is exactly the kind of information I like to be made aware of. However, I do not understand why passing a function pointer can inline the function itself. After all, the function pointed to can only be known at run-time. The only case I can think of where this would work is when the compiler is certain about the value of the function pointer. But maybe I'm missing something entirely? – dgrine Feb 10 '16 at 11:18

2 Answers2

3

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.

Community
  • 1
  • 1
WhiZTiM
  • 21,207
  • 4
  • 43
  • 68
  • This is indeed my line of reasoning. The only thing that's holding me back is the question of 'state'. So more in the line of auto calculate = CalculateSomething(config); calculate(myObject); Do you see any issues with this? Or would you still prefer this approach (and why)? Thank you. – dgrine Feb 09 '16 at 10:35
  • If `CalculateSomething` isn't a lightweight class in terms of state, I think explicit method may be better... Other than that, I still prefer this – WhiZTiM Feb 09 '16 at 10:57
1

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.

Werolik
  • 923
  • 1
  • 9
  • 23
  • I apologize, the class' name was indeed more akin to SomethingCalculator. The reason a lambda cannot be used is that the object holds some state and does some preparatory calculation when constructed. This info is then also used for each call to 'operator()' or 'calculate'. – dgrine Feb 09 '16 at 10:53
  • Are you sure that `Run()`, `DoWork()`, `Calculate()` are more meaningful than `operator()` ? – Jarod42 Feb 09 '16 at 10:54
  • @OnMyLittleDuck, Jarod42, let's consider that it cannot be stateless (that's a topic for another discussion) and that it has to be an object. I still prefer having explicit name for the operator(), because when you see it, you immediately understand that you deal exactly with an object. Basically, that's all. Anyway, you shouldn't be 'religious' about that things - do whatever best suits the situation and/or coding conventions of the projects. Oh, and write comments. – Werolik Feb 10 '16 at 10:02