Why can't we declare a namespace within a class?
Asked Answered
C

6

79

Declaring a class within a class is valid. (Nested classes)

Declaring a namespace within a class is invalid.

The question is: is there any good reason (other than c++ grammar/syntax problems) to forbid the declaration of a namespace within a class ?


As for why would i want to do that, here is an exemple :

Let's have a basic delcaration of a binary tree container

template<typename Data>
class binary_tree
{
 public:
  ... stuff ....     

 private:
  ... iterators class declaration ...

 public:
  typedef left_depth_iterator_impl     left_depth_iterator;
  typedef right_depth_iterator_impl    right_depth_iterator;
  typedef left_breadth_iterator_impl   left_breadth_iterator;
  typedef right_breadth_iterator_impl  right_breadth_iterator;

  ... stuff ....     

 private:
  Data         data;
  binary_tree* left;
  binary_tree* right;
};

Now i notice that there are a lot of iterators in my class, so i would like to regroup them within the same namespace like this :

template<typename Data>
class binary_tree
{
 public:
  ... stuff ....     

 private:
  ... iterators class declaration ...

 public:
  namespace iterator
  {
    typedef left_depth_iterator_impl     left_depth;
    typedef right_depth_iterator_impl    right_depth;
    typedef left_breadth_iterator_impl   left_breadth;
    typedef right_breadth_iterator_impl  right_breadth;
  }

  ... stuff ....     

 private:
  Data         data;
  binary_tree* left;
  binary_tree* right;
};

This would allow a simple usage :

void  function()
{
  binary_tree::iterator::left_depth   it;

  ...stuff...
}

This works if i use a class instead of a namespace, but i am then forced to declare a class that will never be instantiated which is quite a namespace.

Why allow nested classes and forbid nested namespaces within classes ? is it a legacy burden ?


Answers with semantic reasons that do not only quote part of the standard(especially syntax parts) will be apreciated :)

Codeine answered 21/11, 2012 at 0:10 Comment(4)
See Eric Lippert's answer at #8671927 Excerpts: Features are unimplemented by default The absence of a feature does not need justification. Rather, all features must be justified by showing that their benefits outweigh their costs. As the person proposing the feature, the onus is on you to describe why you think the feature is valuable; the onus is not on me to explain why it is not.Ranjiv
you can do... #define inclass_namespace struct.. and you can use it like that...Lomeli
I had the same question as @drax after I read about Smalltalk and its method protocols, which are used to group methods by their purpose. See The Art and Science of Smalltalk, page 66, ch. 'The Standard Protocols'. The purpose of protocols is to help programmers who write the class and those using it.Gawen
I think what @RobertCooper said may be valid, but It also has good chance that a feature is actually proposed but rejected for some reason. Or there already exist better alternative.Nipha
E
8

There's no real advantage to adding such a feature to the language. Features generally don't get added unless there's demand.

What would namespaces inside classes buy you? Would you really rather say binary_tree::iterator::left_depth instead of simply binary_tree::left_depth? Perhaps if you had multiple namespaces inside, you use them to distinguish say binary_tree::depth_iterator::left and binary_tree::breadth_iterator::right.

In any event, you can achieve the desired result using internal classes as a poor-programmer's namespace, which is even more reason why there isn't demand for true namespaces inside classes.

Eonism answered 21/11, 2012 at 0:20 Comment(10)
"Features generally don't get added unless there's demand." We are talking about C++, right?Labanna
It'd be useful for templating where a class uses something inside a namespace as "its" version of something. e.g. T::Namespace::EnumValueKeavy
Namespaces are (almost) entirely syntactic sugar, in and outside of classes. So why have thaem at all?Siege
It would be useful when you don't want to mix up variables with similar names (because they do a similar thing, but at different locations in the code). Sure, there are always different ways to achieve that, but namespaces inside classes would be an easy solution to that, when you don't want to use extra structs for that.Assentation
@einpoklum: "Namespaces are (almost) entirely syntactic sugar, in and outside of classes. So why have them at all?" Sure, let's go back to the flat, fragile, awkward, incomplete, inflexible, overly verbose, repetitive (etc. etc.) VOLUNTARY_NAMING_CONVENTIONS and Static::items::for::scoping) instead of proper, compiler-backed, "semantic", flexible (etc.) "real" namespaces.Ivanna
@Sz.: I was being sarcastic. Of course namespaces are useful - but for the same reasons, they're useful within classes as well.Siege
Bit of an old answer but I can give you an answer to it: creating proper namespaces for enums. I know I should use enum class but that isn't always available in embedded systems compilers as they are notoriously under-supporting of C++ features. A namespace inside of a class would've at least enabled me to scope them properlyVerjuice
I would rather use that function to qualifiers) actually. That is the ask of the question, which is my ask too.Wastepaper
@TarickWelling using enum classes also restrict the variation in data types you can have. I can have many different datatypes in a namespace, which I would love to be able to have within a class so that I can segregate my code.Boyla
"There's no real advantage to adding such a feature to the language." Maybe none that you can think of.Kiefer
A
65

Since you asked which parts of the standard mandate namespace location, we hit that up first:

C++11 7.3-p4: Every namespace-definition shall appear in the global scope or in a namespace scope (3.3.6).

Regarding class definitions and the proposition of declaring a namespace within, I bring you to...

C++11 9.2-p2: A class is considered a completely-defined object type (3.9) (or complete type) at the closing } of the class-specifier. Within the class member-specification, the class is regarded as complete within function bodies, default arguments, exception-specifications, and brace-or-equal-initializers for non-static data members (including such things in nested classes). Otherwise it is regarded as incomplete within its own class member-specification.

Ergo, a class definition is finite once the closing curly is reached. It cannot be opened back up and extended (derivation is something different, but it is NOT extending the class just defined).

But lurking at the very beginning of the standard definition of a namespace is the ability to extend it; to expand it for lack of a better term:

C++ 7.3-p1: A namespace is an optionally-named declarative region. The name of a namespace can be used to access entities declared in that namespace; that is, the members of the namespace. Unlike other declarative regions, the definition of a namespace can be split over several parts of one or more translation units. (emphasis added).

Therefore, a namespace within a class would violate the definition in 7.3-p4. Assuming that was not present, it would be possible to declare a namespace anywhere, including in a class, but since the definition of a class is formalized once it is closed, you would be left with only the ability to do the following if you maintained compliance with 7.3-p1:

class Foo
{
   namespace bar
   {
       ..stuff..
   }

   .. more stuff ..

   namespace bar
   {
       ..still more stuff..
   }
};

The usefulness of this feature was likely debated for about 3-full-seconds before 7.3-p4 was established to settle it.

Asset answered 21/11, 2012 at 0:35 Comment(5)
Therefore, a namespace within a class would violate the definition in 7.3-p4. Did you mean [...] in 7.3-p1?Guide
Well, that's a pure technicality. You could add an exception to the extensibility clause saying that only namespaces outside of a class scope can be extended. Easy peasy.Siege
Thanks for the answer, its good to know the reason behind this.Preferential
"The usefulness of this feature was likely debated for about 3-full-seconds before 7.3-p4 was established to settle it." Not exactly how discussion ever really work. The discussion would turn into one on whether 7.3-p4 itself makes any sense. Namespaces would be a much more powerful tool without 7.3-p4 than with, is the entire argument being made here.Ledda
I appreciate the reference to the standard, but it seems like C++11 7.3-p4 is the only explicit conflict here, and there is no reason that couldn't be amended. As per Robert Cooper's comment, the feature doesn't exist simply because no-one has made a convincing case for adding it.Maramarabel
E
36

I'm going to disagree with others here. I wouldn't say there's no real advantage. Sometimes I'd just like to segregate code without extra implications. As an example, I was working in a multithreaded ringbuffer module and wanted to split the state members, some of which are atomic and/or memory-aligned, into namespaces for the producer and the consumer.

By just naming everything with producer or consumer prefixes (which is my current annoying implementation), I'm adding pollution that makes code harder to read. E.g. when everything owned by the producer starts with producer, it's easier for your brain when reading it to accidentally autocorrect producerProducerTimer (producer copy of a producer timer) as producerConsumerTimer (producer shadow of a consumer timer) or consumerProducerTimer (consumer shadow of a producer timer). Debugging that takes way longer than it needs to because the code is no longer skimmable.

By creating a nested class/struct:

  • I could be giving the next developer who maintains this code the idea that more than one of these could/should be instantiated, copied, and assigned to one another within a context, so now instead of just worrying about naming I also have to = delete these things.
  • I could be adding memory footprint to the context with structural alignment padding that might not otherwise be necessary.
  • Making all members static isn't an option, since more than one context can be instantiated that will need its own producer/consumer state variables.
  • Functions of such a struct no longer have access to other member data or functions, such as constants or functions that are shared by both sides, but instead have to take these things as arguments.

Ideally, I'd like to be able to change things like this:

rbptr producerPosition;
rbptr consumerPosition;

to this:

namespace producer
{
    rbptr position;
}
namespace consumer
{
    rbptr position;
}

Then, functions that should only touch consumer members can use the consumer namespace, functions that should only touch the producer members can use the producer namespace, and functions that need to touch both have to explicitly qualify them. There'd be no way to accidentally touch a consumer variable in a function that's only using the producer namespace.

In this case, the desire is purely for reducing naming collisions between producer and consumer copies of things, and reducing naming collisions are what namespaces exist for. For that reason, I support the proposal to be able to declare namespaces inside classes.

Exaction answered 13/7, 2017 at 17:38 Comment(3)
I do share this opinion, the marked answer is marked as accepted because it does answer the question "why this is not the case currently" to which the main answer is "you can do it poorly with another feature so no one proposed this yet", this doesn't mean it has to stay this way, and i would also support such a proposal, the day someone makes it :)Codeine
Add get&set operators (cast + assign) and you have properties (for free - another feature of namespace inside class/struct).Salim
I support this feature.Goldfinch
E
8

There's no real advantage to adding such a feature to the language. Features generally don't get added unless there's demand.

What would namespaces inside classes buy you? Would you really rather say binary_tree::iterator::left_depth instead of simply binary_tree::left_depth? Perhaps if you had multiple namespaces inside, you use them to distinguish say binary_tree::depth_iterator::left and binary_tree::breadth_iterator::right.

In any event, you can achieve the desired result using internal classes as a poor-programmer's namespace, which is even more reason why there isn't demand for true namespaces inside classes.

Eonism answered 21/11, 2012 at 0:20 Comment(10)
"Features generally don't get added unless there's demand." We are talking about C++, right?Labanna
It'd be useful for templating where a class uses something inside a namespace as "its" version of something. e.g. T::Namespace::EnumValueKeavy
Namespaces are (almost) entirely syntactic sugar, in and outside of classes. So why have thaem at all?Siege
It would be useful when you don't want to mix up variables with similar names (because they do a similar thing, but at different locations in the code). Sure, there are always different ways to achieve that, but namespaces inside classes would be an easy solution to that, when you don't want to use extra structs for that.Assentation
@einpoklum: "Namespaces are (almost) entirely syntactic sugar, in and outside of classes. So why have them at all?" Sure, let's go back to the flat, fragile, awkward, incomplete, inflexible, overly verbose, repetitive (etc. etc.) VOLUNTARY_NAMING_CONVENTIONS and Static::items::for::scoping) instead of proper, compiler-backed, "semantic", flexible (etc.) "real" namespaces.Ivanna
@Sz.: I was being sarcastic. Of course namespaces are useful - but for the same reasons, they're useful within classes as well.Siege
Bit of an old answer but I can give you an answer to it: creating proper namespaces for enums. I know I should use enum class but that isn't always available in embedded systems compilers as they are notoriously under-supporting of C++ features. A namespace inside of a class would've at least enabled me to scope them properlyVerjuice
I would rather use that function to qualifiers) actually. That is the ask of the question, which is my ask too.Wastepaper
@TarickWelling using enum classes also restrict the variation in data types you can have. I can have many different datatypes in a namespace, which I would love to be able to have within a class so that I can segregate my code.Boyla
"There's no real advantage to adding such a feature to the language." Maybe none that you can think of.Kiefer
C
4

This is just not the point of namespaces. Namespaces are meant to exist closer to the top level of code so that if two different companies (or code bases) can mix code with each other. At a more micro level, I code with both IMAP for email access and SMTP for email sending and (could, I am simplifying greatly) have classes in either module called Email that are quite different, but I could have an application, say a mail client, that wants to use both from the same class, e.g. perhaps it forwards mails from one account to another. Namespaces / package names / etc. permit this.

What you have proposed simply isn't what namespaces are for - within one file you are able to give things different names since the author has global knowledge of the file, although this isn't true when two companies want to share code or two applications that didn't know they would be colliding at any point.

Cheng answered 21/11, 2012 at 0:15 Comment(0)
S
3

Just a small thought that I felt was worth mentioning. One use of namespaces inside of classes would be a functional equivalent to templated namespaces.

template<class...types>
struct Namespace {
    namespace Implementation {
        ...
    }
};

// somewhere else

using namespace Namespace<types...>::Implementation;

// use templated stuff.

Personally, I would enjoy this feature, but it seems the demand isn't high enough for it to be implemented.

Soothsay answered 16/8, 2018 at 19:11 Comment(3)
This would also be useful to import a nested enum type's values in a new scope.Peruke
@Peruke yeah. Classes and namespaces are quite similar, so I'm unsure as to why so many are against this idea.Soothsay
@AnthonyMonterrosa, part of it is just the usual deeply rooted "cling to what you own" attitude, overlapped with what's so eloquently written in the classic bikeshedding "antirant" of Poul-Henning Kamp. And then part of it is that changing anything in the several decades old, huge, and already freaking complex C++ specs is hard and risky.Ivanna
C
0

i'm going to get hate for this probably

template<typename Data>
class binary_tree
{
 public:
  ... stuff ....     

 private:
  ... iterators class declaration ...

 public:
  class iterator
  {
    iterator() = delete;
  public:
    typedef left_depth_iterator_impl     left_depth;
    typedef right_depth_iterator_impl    right_depth;
    typedef left_breadth_iterator_impl   left_breadth;
    typedef right_breadth_iterator_impl  right_breadth;
  }

  ... stuff ....     

 private:
  Data         data;
  binary_tree* left;
  binary_tree* right;
};

this is basically a static class that cannot be instanciated so you have to access the typedefs inside it using iterator::type so you now can use it as a regular namespace

void  function()
{
  binary_tree::iterator::left_depth   it;

  ...stuff...
}
Cosmopolitan answered 5/3, 2022 at 19:31 Comment(6)
Hi, The option of nested classes is already mentioned in the accepted answer. In any case please note that just posting code without explaining how the code answers the question is not a good practice. Please edit your answer to explain what is your suggestion and how it is good. Also please note that the OP clearly states in the question that he is aware of nested classes. Hi asks for the reason not for a work around.Hypno
yes i will add detailsCosmopolitan
but the answer gives a different way of doing it. i did exactly what they wanted. a namespace inside of a classCosmopolitan
ok so OP is aware but didn't provide any code. i answered cause i know someone is going to ask the same question and probably won't read the entire question. sometimes you gotta answer for someone else.Cosmopolitan
Your are correct that the accepted answer suggests using nested classes (just as your answer does). But as you can see it is not the answer with the most votes. It is OK you want to show a good solution for someone else. By all means. As I wrote - you need to elaborate and explain your solutionHypno
I elaborated as much as I can but I can't really find anything else to elaborateCosmopolitan

© 2022 - 2024 — McMap. All rights reserved.