When to use a namespace or a struct?
Asked Answered
A

7

15

I was just reading a little bit on them from http://www.cplusplus.com/doc/tutorial/namespaces/ and it seems like a struct is capable of the same things? Or even a class for that matter. Maybe someone here can better define what a namespace is, and how it differs from a struct/class?

Aerophone answered 10/4, 2010 at 17:55 Comment(0)
T
24

Namespaces and class-types are not capable of the same things. Namespaces are mainly used to group types and functions together to avoid name collisions, while class-types hold data and operations that work on that data.

To just group functions and objects by using a class-types you'd have to make them static:

struct X {
    static void f();
};

Without static you'd have to create instances of the class-types to use them. A namespace is much better suited here:

namespace X {
    void f();
}

Another important thing are using declarations and directives:

namespace X {
    void f();
    void g();
}

void h() {
    using X::f;
    f(); // f() now visible in current scope
    using namespace X;
    f(); g(); // both visible
}

With class-types there simply is no mechanism that allows that.

What class-types give you over namespaces is that you can have multiple instances with differing state - if you need that use a class-type.

Tavy answered 10/4, 2010 at 18:11 Comment(3)
On top of that, structs and namespaces were meant for solve different problems. So when you use a namespace you communicate something else about what you try to achieve than when you use a struct.Orourke
the "using" construct is ill-advised in many situations. the maintainer is often more aware of that than the user. if a maintainer wants to ensure the explicit use of his library in a setting with large numbers of developers, it may be advised to use struct/static instead. i like to preface this sort of usage with an explanation: struct X { // create an explicit-only namespaceBoehmenism
Namespace usage would probably be better controlled with style rules (via review or linting rules) instead of overloading other constructs.Tavy
S
11

Well, seems everyone's going at it, so I'll add my own arguments.

First things first, namespace and struct are completely different beasts: they have different syntax and different semantics.

The obvious:

  • a struct introduces a type, you can use as templates argument
  • a namespace can be spread in several files

Syntactically:

  • both can be "aliased", namespace with namespace ns = mylong::name::space; and struct with typedef mylong::name::Space lilstruct;
  • ADL (or Argument Dependent Lookup) is tailored for namespaces

Semantically:

  • a namespace only defines a scope for the definition of symbols, which allows to group together objects that work together (classes and free-functions) while isolating them for the rest of the world (name clashes). As such it often represents a logical unit of work within the project (for small projects, there is a single namespace).
  • a struct or class defines a logical binding between data and the methods to act upon it, which is the corner stone of encapsulation. It usually has one clear responsability and a number of invariants.

Note that sometimes a struct or class is just used to bind together objects that work together without having any logic, for example struct Person { std::string name, firstName; };.

That being said: there is no point in C++ for a struct of static methods. It's just a perversion from Java or C# and their "pure" OO approach. C++ supports free functions, so there is no point not using them, especially since it's better for encapsulation (they don't have access to private/protected parts, so you can't mess up an invariant and they don't depend on the representation of the class either).

Silverweed answered 11/4, 2010 at 12:10 Comment(1)
This might not be the top answer, but this is a great answer still. It really explains the how and why. Love it!Rooftree
B
5

If you don't want people to use the "using" feature of C++ with your class, which can be dangerous and is often ill advised in complex code, then go ahead and use struct with statics.

In other words: if your functions should always be referred to with "group::function", then you can box in your users by declaring as a struct.

In addition, and importantly, you can forward-declare structs in older versions of C++. You cannot do this with namespaces until C++ 11.

Consider:

std::string out zip::pack(const std::string &in)
std::string out zip::unpack(const std::string &in)

In this case, requiring users to specify zip:: makes sense. It's a short, specific and informative. And the names of the underlying functions are ambiguous without it. Use a struct with statics.

Consider:

std::string out CorpDataUtils::zipPack(const std::string &in)
std::string out CorpDataUtils::zipUnpack(const std::string &in)

These should certainly be in a namespace. The namespace name is long, and uninformative, probably more to do with the organization of whoever is maintaining it - which is fine... but really it should be a namespace... not a struct.

Boehmenism answered 9/2, 2016 at 14:47 Comment(0)
C
4

If it can be done with a namespace, use a namespace.

A struct does much more than defining a scope. It defines a type.

Camellia answered 10/4, 2010 at 18:5 Comment(1)
I find nested namespaces really annoying when they're not consisted. For example, I hate that some libraries in Boost have their own nested namespaces, while others don't because it isn't uniform. Why is it ok to say boost::bind() but you have to say boost::assign::list_of()? Either always put a project in a namespace of its own, or never do -- so your users will intuitively use your names correctly on the first try.Orourke
T
2

In C++ a struct is exactly the same as a class, except structs are public by default. Classes are private. So whenever you want to group free functions together use a namespace. When you want to group data and functions, use a struct/class, and optionally a namespace around it all.
Notice that If you put your functions in a struct then you would have to have an instance of your struct when you want to call those functions, unless they are static.

Tetanize answered 10/4, 2010 at 18:1 Comment(2)
"When you want to group data and functions, use a struct/class, and optionally a namespace around it all": Wrong. That's not how you choose between the two.Orourke
How would you choose between the two?Pesky
G
2

When creating your own library, it's normally good practice to namespace all your exported functions and classes.

That way, if someone includes your library, they won't be polluting their namespace, and there is less likelyhood of name clashes.

Goingover answered 10/4, 2010 at 18:5 Comment(0)
M
2

This is a counter example where using a struct instead of a namespace gives some unexpected benefits.

I wanted to generalise a solution to a 2D problem to K dimensions. The 2D solution was enclosed in a namespace.

Templates to the rescue. I started changing the implementation:

struct Point;

to

template< size_t DIMS >
struct Point;

I needed to template most classes, structs, and functions. That was tedious, repetitive, and error prone. And then I had this mischevios idea. I changed

  namespace KDimSpace {

to

  template< size_t DIMS >
  struct KDimSpace {

and that was pretty much it. I could rip off all template< size_t DIMS > junk inside. This is so much easier - the number of dimensions DIMS is declared only once and used consistently by all types and functions.

And then, there is one more thing - rather than hiding internals of the implementation behind ::detail (sub)namespace there is public: and private:!

There are two annoyances:

  • functions have to be marked as static
  • it is not possible to define operators (e.g. operator<< for std::ostream) because operators cannot be marked as static (and then ADL might get in the way as well).

Bottom line - C++ could be a better language with fewer primitives not more. I would like namespaces to be as close to structs as classes are.

Melan answered 3/12, 2022 at 19:25 Comment(1)
This is exactly the kind of answer I was looking for. However I found an extra benefit, functions in a struct can call each other even if they are defined out of order, without needing functions declarations. Namespaces require you to forward declare or define foo before you call it. Example code: godbolt.org/z/s47jTPq4zKorten

© 2022 - 2024 — McMap. All rights reserved.