3

The Short (Original) Version

How are function objects, sometimes called "functors" in C++ and other OO languages, where they make sense different from classes symptomatic of the poltergeist anti-pattern?

Definitions

  • A function object is a construct allowing an object to be invoked or called as if it were an ordinary function (full definition, more references follow).
  • A poltergeist is a short-lived object, typically stateless, which is used solely to trigger or initialize several other objects and then discarded. It is considered a consequence of poor object design (full definition, more references follow).

Why Do I Ask?

In many places in the extensive code-base I'm working on, a complex data structure is being traversed in a few different ways, and each element is being acted upon. In order to not violate the DRY principle by re-writing the complex traversal code and its variants, I instead have several higher-order traversal functions which accept function objects that act on elements as arguments. Likely, (C++) iterator pattern is warranted here, but it was missing and its implementation is costly, so I deferred it.

I had a concern that these multiple function objects would obfuscate my code and make it less maintainable, but instead of asking "do these make my code more obscure", which seems like an opinion-based question, so I alluded to more-or-less known things with concrete definitions. I did not quite understand why function objects cannot all be classified as poltergeists / bad design before the answer was kindly provided below by Karl Bielefeldt.

Additional References

Poltergeists:

Originally, this question also included this article here, which likely means it's also in the book Design Patterns Explained Simply, but [disclaimer] people took issue with this article in the comments for reasons seemingly unrelated to the actual concept.

Object functions:

Clarifications, or What This Question is Not About

  • This question is neither about how well-known the term "poltergeist anti-pattern" is, nor is it about whether it discourages or encourages good or bad coding practices. Please refer to the Wikipedia article on possible confusions about this concept.

  • This question is not about what is and what isn't a functor. The term "functor" means different things in the context of functional programming and the context of object-oriented languages. This question refers to function objects, i.e. the latter definition.

  • 4
    Linked article makes Adapters a BAD thing, and proposes to replace glue code with high coupling. Throws cohesion out of the window too. – Basilevs May 3 '18 at 15:28
  • @Basilevs, so, do you mean to say that there is no difference? That could be a perfectly valid answer to this question, unless I'm missing something. – Greg Kramida May 3 '18 at 15:44
  • 1
    No, I don't know rhe answer. I'm just a bit disappointed with article. – Basilevs May 3 '18 at 15:54
  • 2
    I'm struggling to understand what that author is complaining about, and what they think the solution is. It doesn't seem related to "objects that are also functions". – Caleth May 3 '18 at 16:03
  • 1
    @amon, I appreciate the opinion, should I include more references to indicate that this isn't just one blogger but a widely-known concept? For instance, there is this book here: Brown, William J. (1998). "Chapter 5: Software Development AntiPatterns". AntiPatterns: Refactoring Software, Architectures, and Projects in Crisis. New York, USA: John Wiley & Sons. Other online examples: sergeyzhuk.me/2017/05/11/antipattern-poltergeist sahandsaba.com/… antipatterns.com/briefing/index.htm (etc.) – Greg Kramida May 3 '18 at 19:34
9

First of all, be careful about calling them functors, because apparently C++ people ignored the entire history of what functor means and decided to redefine that name for their function objects, which is a completely different thing than what most people think of as a functor.

Second, the poltergeist anti-pattern requires doing something unexpected via side effect. If your operator() method has side effects, then it could certainly qualify as an example of that anti-pattern. However, there are also uses of operator() that don't have side effects, such as emulating partial function application. Those uses may potentially have other anti-patterns, but without unexpected side effects, it wouldn't be a poltergeist pattern.

  • Thank you, I will edit my question to reflect your note about the functor nomenclature. – Greg Kramida May 3 '18 at 16:07
  • 4
    Is "poltergeist pattern" even a thing? The article freely states that they came up with the name themselves as a descriptive term, so I doubt very much that it is a well-known software (anti)pattern. – Robert Harvey May 3 '18 at 17:11
  • 3
    The pattern is common, even if the name isn't. – Karl Bielefeldt May 3 '18 at 17:39
  • 1
    I've come to believe the proliferation of multiple names for the same thing in our field is driven by the need to spread names unique enough to drive us to their blog. – candied_orange May 4 '18 at 1:08
  • Sounds like every lambda with side effects is a poltergeist. What a silly "anti-pattern". – Frank Hileman May 4 '18 at 18:48
4

Very simple, potentially short-lived objects are damn useful in many scenarios; yes, what they mistakenly call "functors" (partially-applied functions), tuples, optionals, etc match this pattern.

If one cares about utter efficiency and not ever allocating an extra byte, one should first detect the hot code path, and optimize it. For the rest of the design (likely 99% of it), such optimizations do not bring any benefit.

Anything that helps thinking about the program more easily and clearly does bring a benefit.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.