3

This example shows a function named validate defined at global scope overloading a function in the boost::program_options namespace.

What justifies this design using a global function to overload? Why is a more tightly-scoped design not implemented by boost::program_options instead (e.g. overriding a class method, or some other scheme)?

As noted in comments below, my main concern is really that a user might be surprised to find that one of their global functions is being called by the library.

It should be emphasized that namespaced free functions are extremely important (as opposed to global-scope free functions, see this link provided by Chris Drew). Indeed, namespaced, non-class (free) functions are IMO a major benefit of C++.

My company is considering a major adoption of Boost, it seems to be highly regarded. But, this particular design decision has me concerned.

user2141130
  • 954
  • 7
  • 22
  • 1
    What exactly is wrong with a free function? Not everything needs to be stuck in a class. And `validate` doesn't need to be in the global namespace, you can place it in the same namespace as the type you're validating, ADL will find it. – Praetorian Jul 14 '15 at 16:54
  • @Praetorian your rhetorical question "What exactly is wrong with a free function?" is essentially my question from a different angle. If the answer to that question is "nothing" or "in this situation the benefits outweigh the drawbacks" then what are those benefits? – user2141130 Jul 14 '15 at 17:02
  • 2
    Praetorian is right, in fact Scott Meyers [teaches us](http://www.amazon.co.uk/Effective-Specific-Programs-Professional-Computing/dp/0321334876) to [prefer non member functions to member functions](http://www.drdobbs.com/cpp/how-non-member-functions-improve-encapsu/184401197) – Chris Drew Jul 14 '15 at 17:08
  • Well, the obvious benefit is not muddling your class' interface by adding a function that adds no functionality to the class itself. `validate` is meant to check whether some string provided by the user fits an expected format, so I think you'll agree that it's of little use to the users of your class otherwise. – Praetorian Jul 14 '15 at 17:10
  • I think my main surprise is that a function defined in a `namespace` can be overloaded (hidden) by a function defined at global scope. I'm going to ask why c++ allows that and whether anyone considers that a flaw unless you have a brief explanation handy. – user2141130 Jul 14 '15 at 17:12
  • This question is not about class methods vs (namespaced) free functions (I often prefer namespaced free functions to class methods). My concern is that a user-defined global function is being called by library code in a surprising way. You could argue that the signature of `validate` makes it unlikely to be accidentally overridden. This is a weak defence: imagine the only parameter of library's `validate` is `T*` then a function like `validate(Foo *)` would be called by the library. What are best practices here? – user2141130 Jul 14 '15 at 18:10
  • At the very least this is an example against defining global functions unless you know that they are being used as overrides in this way. Even then, what prevents another, unrelated library from doing the same thing. At this point this is looking more like a deficiency rather than a good use of free functions (again, I often prefer them over class methods as prescribed by the Meyer's article). Therefore Andre's answer is looking more likely. – user2141130 Jul 14 '15 at 18:15

2 Answers2

2

I think my main surprise is that a function defined in a namespace can be overloaded (hidden) by a function defined at global scope. I'm going to ask why c++ allows that and whether anyone considers that a flaw unless you have a brief explanation handy. user2141130 2 hours ago

No that cannot be considered a flaw.

The function will not be hidden by a function defined at global scope.

This is what Argument Dependent Lookup (ADL) is for, and you've been using it all around! You use it here:

std::cout << "Hello world!";

ADL is pretty subtle and pretty pervasive. Many people don't realize it until they ask themselves the same kind of question you just asked. Free function work really nicely for extension points.

More: What is "Argument-Dependent Lookup" (aka ADL, or "Koenig Lookup")?

Community
  • 1
  • 1
sehe
  • 374,641
  • 47
  • 450
  • 633
  • Ok, so my comment that a function with the signature `validate(Foo *)` could accidentally be written and then called by the library is wrong. Correct? – user2141130 Jul 14 '15 at 20:14
  • Yes. Worst case it would be ambiguous (but for that to happen it should be equally applicable for the argument types; this is rarely the case). – sehe Jul 14 '15 at 20:16
1

In general, different boost libraries have different level of quality.

More specifically, this covers relatively rare user case. I guess it would be possible to implement it differently, but the author chose a quick and simple route. While I would agree that a global function is not perfect, it's certainly not as bad as, say, global variable. These validate functions will be by nature limited to main.cpp or similar.

Of course you are welcome to either suggest improvements to the library or use alternative implementations. I can assure you that there are a lot very useful and well designed libraries in boost, so let this example not discourage you.

Andre
  • 637
  • 6
  • 16
  • _"These validate functions will be by nature limited to main.cpp or similar"_ misses a point. The issue of ODR would still be there, arguably even worse, because of the unexpectness of impact outside the main TU – sehe Jul 14 '15 at 23:05
  • Sure, they will be in the global scope (bad). But if there is a clash, you know where to look for them (good) :) The world is not perfect – Andre Jul 15 '15 at 13:27
  • It wasn't about the scope. Even at namespace scope, defining the same symbols in different TUs risks violating the ODR. So it would require the implementations to be file-static (not have external linkage/visability). – sehe Jul 15 '15 at 13:57