views:

680

answers:

5

Let's say I have, or am going to write, a set of related functions. Let's say they're math-related. Organizationally, should I:

  1. Write these functions and put them in my MyMath namespace and refer to them via MyMath::XYZ()
  2. Create a class called MyMath and make these methods static and refer to the similarly MyMath::XYZ()

Why would I choose one over the other as a means of organizing my software?

+3  A: 
  • If you need static data, use static methods.
  • If they're template functions and you'd like to be able to specify a set of template parameters for all functions together then use static methods in a template class.

Otherwise, use namespaced functions.


In response to the comments: yes, static methods and static data tend to be over-used. That's why I offered only two, related scenarios where I think they can be helpful. In the OP's specific example (a set of math routines), if he wanted the ability to specify parameters - say, a core data type and output precision - that would be applied to all routines, he might do something like:

template<typename T, int decimalPlaces>
class MyMath
{
   // routines operate on datatype T, preserving at least decimalPlaces precision
};

// math routines for manufacturing calculations
typedef MyMath<double, 4> CAMMath;
// math routines for on-screen displays
typedef MyMath<float, 2> PreviewMath;

If you don't need that, then by all means use a namespace.

Shog9
so called static data can be namespace level data in the implementation file of the namespace, this reduces coupling even more since it doesn't have to show up in the header.
Motti
Static data is no better than namespace-scope globals.
coppro
@coppro. They are at least one step up the evolutionary chain from random globals as they can be made private (but otherwise agree).
Martin York
@Motti: OTOH, if you *want* it in the header (inline / template functions), you're back to being ugly about it.
Shog9
+12  A: 

There are a lot of people who would disagree with me, but this is how I see it:

A class is essentially a definition of a certain kind of object. Static methods should define operations that are intimately tied to that object definition.

If you are just going to have a group of related functions not associated with an underlying object or definition of a kind of object, then I would say go with a namespace only. Just for me, conceptually, this is a lot more sensible.

For instance, in your case, ask yourself, "What is a MyMath?" If MyMath does not define a kind of object, then I would say: don't make it a class.

But like I said, I know there are plenty of folks who would (even vehemently) disagree with me on this (in particular, Java and C# developers).

Dan Tao
You have a very pure perspective on this. But practically speaking, a class with all-static methods can come in handy: you can `typedef` them, use them as template parameters, etc.
Shog9
That's becuase Jave and C# people don't have a choice.
Martin York
@shog9. You can templatize functions as well!
Martin York
@Martin: Well yeah, of course. I guess my point is that the tools you use tend to shape the way you think.
Dan Tao
@Martin York: can you pass a namespace as a template parameter?
Shog9
@Shog9: I think if somebody's interested in using a class as a template parameter, that class is almost surely defining some underlying object. Take this question as an example: What kind of template function would take MyMath as a parameter?
Dan Tao
@Dan: presumably, one that needed math routines and wanted to support "plugging in" different implementations.
Shog9
@Shog9: That isn't to say I don't appreciate your pragmatic take, though. The additional benefits of using a static class are certainly not nothing.
Dan Tao
@Dan: and by the same token, i'm not trying to *promote* static classes here - they *are* over-used, at least in much of the code i've seen. But they do have their uses.
Shog9
@Dan: "I think if somebody's interested in using a class as a template parameter, that class is almost surely defining some underlying object." No, not at all. Think of traits. (Nevertheless, I fully agree with your answer.)
sbi
@Shog: never thought about the template argument. Very nice.@Martin: you can't use the namespace MyMath as a template parameter. I think that is what Shog was talking about.
D.Shawley
+2  A: 

I would prefer namespaces, that way you can have private data in an anonymous namespace in the implementation file (so it doesn't have to show up in the header at all as opposed to private members). Another benefit is that by using your namespace the clients of the methods can opt out of specifying MyMath::

Motti
You can have private data in an anonymous namespace in the implementation file with classes, too. Not sure I follow your logic.
Patrick Johnmeyer
+2  A: 

You should use a namespace, because a namespace has the many advantages over a class:

  • You don't have to define everything in the same header
  • You don't need to expose all your implementation in the header
  • You can't using a class member; you can using a namespace member
  • You can't using class, though using namespace is not all that often a good idea
  • Using a class implies that there is some object to be created when there really is none

Static members are, in my opinion, very very overused. They aren't a real necessity in most cases. Static members functions are probably better off as file-scope functions, and static data members are just global objects with a better, undeserved reputation.

coppro
+2  A: 

By default, use namespaced functions.

Classes are to build objects, not to replace namespaces.

In Object Oriented code

Scott Meyers wrote a whole Item for one of his Effective C++ books on this topic, something like "Prefer non-friend non-member functions to member functions". I found an online reference to this principle in an article from Herb Sutter: http://www.gotw.ca/gotw/084.htm

The important thing to know is that: In C++ functions in the same namespace than a class belong to that class' interface. (because ADL will search those functions when resolving function calls)

namespaced functions, unless declared "friend" have no access to the class' internals, whereas static methods have.

This means, for example, that when maintaining your class, if you need to change your class' internals, you will need to search for side effects in all its methods, including the static ones.

Extension I

Adding code to a class' interface.

In C#, you can add methods to a class even if you have no access to it. But in C++, this is impossible.

But, still in C++, you can still add a namespaced function, even to a class someone wrote for you.

See from the other side, this is important when designing your code, because by putting your functions in a namespace, you will authorize your users to increase/complete the class' interface.

Extension II

A side-effect of the previous point, it is impossible to declare static methods in multiple headers. Every methods must be declared in the same class.

For namespaces, functions from the same namespace can be declared in multiple headers (the almost-standard swap function is the best example of that).

Extension III

The basic cooless of a namespace is that in some code, you can avoid mentioning it, if you use the keyword "using":

#include <string>
#include <vector>

// Etc.
{
   using namespace std ;
   // Now, everything from std is accessible without qualification
   string s ; // Ok
   vector v ; // Ok
}

string ss ; // COMPILATION ERROR
vector vv ; // COMPILATION ERROR

And you can even limit the "pollution" to one class:

#include <string>
#include <vector>

{
   using std::string ;
   string s ; // Ok
   vector v ; // COMPILATION ERROR
}

string ss ; // COMPILATION ERROR
vector vv ; // COMPILATION ERROR

This "pattern" is mandatory for proper use of the almost-standard swap idiom.

And this is impossible to do with static methods in classes.

So, C++ namespaces have their own semantics.

But it goes further, as you can combine namespaces in a way similar to inheritance.

For example, if you have a namespace A with a function AAA, a namespace B with a function BBB, you can declare a namespace C, and bring AAA and BBB in this namespace with the keyword using.

Conclusion

Namespaces are for namespaces. Classes are for classes.

C++ was designed so each concept is different, and is used differently, in different cases, as solution to different problems.

Don't use classes when you need namespaces.

And in you case, you need namespaces.

paercebal
+1 I was wondering how long it would take for someone to mention Koenig lookup :)
Éric Malenfant