29

I find that my C++ header files are quite hard to read (and really tedious to type) with all the fully-qualified types (which goes as deep as 4 nested namespaces). This is the question (all the answers give messy alternatives to implementing it, but that's not the question): Is there a strong reason against introducing scoped using-directive in structs and classes in the C++ language (while it's permissible to have scoped using-declaration in functions)?

e.g.

class Foo : public Bar
{
    using namespace System;
    using namespace System::Network;
    using namespace System::Network::Win32::Sockets;
    using Bar::MemberFunc; // no conflict with this

    // e.g. of how messy my header files are without scoped using-directive
    void FooBar(System::Network::Win32::Sockets::Handle handle, System::Network::Win32::Sockets::Error& error /*, more fully-qualified param declarations... */);
};

Since namespace is a keyword, I would've thought it's distinct enough to cause no conflict with the scoped using declaration such as Bar::MemberFunc.

EDIT: Read the question carefully ---> I've bolded it. Reminder: we're not discussing how to improve readability of the example here. Suggesting how scoped using-directive could be implemented (i.e. by means of adding keywords / constructs etc.) in the C++ language is NOT an answer (if you could find an elegant way to implement this using existing C++ language standards, then it would of course be an answer)!

taskinoor
  • 45,586
  • 12
  • 116
  • 142
Zach Saw
  • 4,308
  • 3
  • 33
  • 49
  • 2
    Personally, I think it's a sign of bad design when there are so many nested namespaces. – Omnifarious Dec 06 '10 at 04:32
  • By your reasoning, the .NET framework would be a bad design. – Zach Saw Dec 06 '10 at 04:35
  • 2
    @Zach Saw - It's bad C++ design, it's not-so-great Java design and it's OK (but still not fantastic) Python design. And if the .NET framework for C++ does that, then yes, it's not very well designed. I do think though that C++ could use a mechanism like you suggested for restricting the scope of a using declaration. That would cause heavily nested namespaces to be a less bad design in C++ than they currently are. – Omnifarious Dec 06 '10 at 05:10
  • 7
    @Omnifarious: You can compare the STL to the more extensive libraries like .NET and Java libs. If the C++ standard lib was more extensive we would definitely need to break it up into more namespaces (and of course spend 5 years coming to compromise over what it is). But we would definitely need some form of nested namespaces. Personally I think it is a good idea but you must be careful. – Martin York Dec 06 '10 at 05:19
  • 1
    @Martin York - I don't think nested namespaces are an evil that should never be visited upon the world. Boost uses them a lot. I just think they should be used sparingly and your nesting depth should be kept small and a given namespace should have a lot of names. The way C++ currently works makes extensively nested namespaces cause problems just like the one the OP is having. – Omnifarious Dec 06 '10 at 05:27
  • 1
    Guys, the question is, "Is there a strong reason not to have this feature in the language?" – Zach Saw Dec 06 '10 at 05:53
  • @Omnifarious: So what's the reason then /not/ to introduce this feature to the language? – Zach Saw Dec 06 '10 at 06:04
  • "Suggesting how scoped using-directive could be implemented in the C++ language is NOT an answer!" <- but it is. If I can show that it can be implemented in C++ now, then that **is** a very strong reason for not explicitly adding such a feature to the language. – jalf Dec 06 '10 at 09:54
  • Perhaps that statement is misleading. But I meant implementing the feature on top of the existing language (i.e. by introducing new constructs / keywords etc.). If you could show that it can be implemented in C++ ***now*** (now being the operative keyword), then of course it's an answer. – Zach Saw Dec 06 '10 at 11:22

5 Answers5

14

Sometimes I do this to achieve almost the same effect:

namespace detail {
    using namespace System;
    using namespace System::Network;
    using namespace System::Network::Win32::Sockets;

    class Foo : public Bar
    {
         void FooBar(Handle handle, Error& error);
    };
}
using detail::Foo;
Timo
  • 5,125
  • 3
  • 23
  • 29
  • 1
    Please read the question carefully before answering. – Zach Saw Dec 06 '10 at 06:12
  • 6
    I saw that. But the question is a bit pointless cause it most likely has no answer. A lot of things in C++ standard don't make sense. – Timo Dec 06 '10 at 06:59
  • 3
    Sometimes the answer to "why isn't X allowed?" is that C++ provides another way of achieving the same thing -- as is demonstrated here. – Brent Bradburn Nov 06 '13 at 18:03
  • This is what I've been trying to work our if it's considered bad practice or not. People seem to say that don't use `using namespace` in a header - but I wonder if they mean in the global space. Is it ok to use `using std:vector` inside a header inside your own namespace before declaring a class that uses a lot of vectors? – thomthom Dec 15 '13 at 22:05
  • 3
    This has the side effect of the user of Foo needing to know it's in the `detail` namespace when Foo needs to be fully qualified to resolve ambiguities (`::Foo`). So no, what's demonstrated here is *not* achieving the same thing. – Zach Saw Mar 06 '14 at 00:37
  • 1
    @thomthom The issue with having using-directives inside a header is that any source file that includes that header, or any source file that includes any other file that includes that header, has those using-directives in it as well, very possibly without the writer of the source file even knowing about it. If it's limited in scope, such as by being placed inside a separate namespace, then this isn't as much of an issue. – Justin Time - Reinstate Monica Jul 01 '16 at 20:22
12

Given that using declarations at class scope are not inherited, this could work. The name would only be valid inside that class declaration, or inside the declarations of nested classes. But I think it's sort of overloading the concept of a class with an idea that should be larger.

In Java and Python individual files are treated in a special way. You can have import declarations that inject names from other namespaces into the file. These names will (well, not exactly with Python, but it's too complicated to explain here) only be visible within that file.

To me that argues for this sort of ability not being tied to a class declaration, but given a scope of its own instead. This would allow injected names to be used in several class declarations if it made sense, or even in function definitions.

Here is an idea I prefer because it allows these things while still giving you the benefits of a class level using declaration:

using {
   // A 'using' block is a sort of way to fence names in.  The only names
   // that escape the confines of a using block are names that are not
   // aliases for other things, not even for things that don't have names
   // of their own.  These are things like the declarations for new
   // classes, enums, structs, global functions or global variables.
   // New, non-alias names will be treated as if they were declared in
   // the scope in which the 'using' block appeared.

   using namespace ::std;
   using ::mynamespace::mytype_t;
   namespace mn = ::mynamespace;
   using ::mynamespace::myfunc;

   class AClass {
     public:
      AClass(const string &st, mytype_t me) : st_(st), me_(me) {
         myfunc(&me_);
      }

     private:
      const string st_;
      mn::mytype_t me_;
   };
// The effects of all typedefs, using declarations, and namespace
// aliases that were introduced at the level of this block go away
// here.  typedefs and using declarations inside of nested classes
// or namespace declarations do not go away.
} // end using.

// Legal because AClass is treated as having been declared in this
// scope.
AClass a("Fred", ::mynamespace::mytype_t(5));

// Not legal, alias mn no longer exists.
AClass b("Fred", mn::mytype_t);

// Not legal, the unqualified name myfunc no longer exists.
AClass c("Fred", myfunc(::mynamespace::mytype_t(5));

This is analogous to declaring a block for local variables in a function. But in this case you are declaring a very limited scope in which you will be changing the name lookup rules.

Omnifarious
  • 54,333
  • 19
  • 131
  • 194
  • Again, the question is, "Is there a strong reason against introducing scoped using-directive in structs and classes in the C++ language?" – Zach Saw Dec 06 '10 at 05:59
  • @Zach Saw - I fixed my answer to actually answer your question. :-) – Omnifarious Dec 06 '10 at 06:04
  • No it won't be the same as my idea. Derived classes won't inherit the using-directive - it's scoped within the class only. So no problem with the ambiguities as per your typedef. – Zach Saw Dec 06 '10 at 06:10
  • @Zach Saw - Hmmm... OK, so that problem doesn't exist because you're right, other kinds of using declarations are not inherited. I still like my `using` scope idea better because I think it's more flexible and clearer. – Omnifarious Dec 06 '10 at 06:14
  • @Omnifarious: Again, that doesn't answer the question. You're arguing that we should have the feature in the language -- the question is, why should we ***not*** have it. – Zach Saw Dec 06 '10 at 06:16
  • 1
    @Zach Saw - My argument is that a different, related feature would actually be better and clearer. – Omnifarious Dec 06 '10 at 06:18
  • @Omni: That's not a feature yet. And we're not discussing how it should look like - we're discussing why shouldn't we have it. – Zach Saw Dec 06 '10 at 06:21
  • 1
    @Zach Saw - And I'm saying we shouldn't have it in the form you're talking about because it's too limited in scope (pun intended) that way. – Omnifarious Dec 06 '10 at 06:24
  • @Omni: That's just an example - to help with the understanding of what I meant by "scoped using-directive within a struct/class declaration". Unless you can find a portable C++ language feature that fulfills this criteria in a more elegant manner, I can't accept your answer. – Zach Saw Dec 06 '10 at 06:40
  • @Omni: Personally, I prefer it to be limited in scope. But that's not what this question is all about. I suppose it would make a great topic for another day if we've decided that there's no reason why C++ shouldn't support this feature to begin with. – Zach Saw Dec 06 '10 at 06:42
  • 1
    @Zach Saw - Personally, I think that the existence of an idea for a more general and/or clearer feature is a perfectly good reason to be against the more limited and less clear feature. – Omnifarious Dec 06 '10 at 06:47
  • @Omni: It's your idea of scope-restricted using-directive vs mine. Again, that's a topic for another day but right now, let's establish if there's a strong reason against introducing it to the C++ language. – Zach Saw Dec 06 '10 at 06:53
  • 3
    Usually, the standards committee works the opposite way. Is there a strong reason for *including* it in the language? C++ is already a huge language. Every new feature *really* has to justify the cost in order to be added. So is such a feature critical enough to justify making the language even bigger? – jalf Dec 06 '10 at 09:52
  • In which case, C++ is doomed to die off as with that reasoning, they'd prefer to favour legacy stuff over introducing new features to make the language more elegant. – Zach Saw Dec 06 '10 at 10:07
  • BTW, is there a *strong* reason for the auto keyword? – Zach Saw Dec 06 '10 at 10:07
  • @Zach Saw - That's an amusing example to pick. In C++0x, the `auto` keyword has been repurposed and there is now an excellent reason to have it. – Omnifarious Dec 06 '10 at 11:18
  • What defines how strong a reason is? Is it objective or subjective? – Zach Saw Dec 06 '10 at 11:26
  • @Zach Saw - Consensus. It's subjective, but driven by the opinions of an entire group, not just one person. I think a strong case can be made for some sort of scoped using declaration, and possibly scoped aliases as well. – Omnifarious Dec 06 '10 at 11:35
  • I guess what I was trying to say is it could always be argued that one should never need anything higher level than ASM. The committee members have always been overly conservative and the enhancements to the language have been very slow to come by. Most vendors have implemented some form of "property" keyword non-standard extension now, and the standard still hasn't caught up. IMHO, I don't think the committee have got the balance right. – Zach Saw Dec 06 '10 at 11:39
  • It should also be noted that it's because this group is made up of people with different (business) interest that it's traditionally been extremely hard to get consensus on *anything*. – Zach Saw Dec 06 '10 at 11:42
  • @Zach Saw - I believe there are function and class 'attributes' in C++0x. And I think that fits the definition of 'property' keyword. – Omnifarious Dec 06 '10 at 16:18
  • @Omni: No they're totally different things. There is however a proposed solution for properties in C++0x but it called Implicitly callable functions (or ICFs) and Implicitly callable member functions (ICMFs). Not sure if it's been dropped from C++0x though. – Zach Saw Dec 07 '10 at 02:01
  • @Zach: These features aren't "legacy staff". On the contrary, C++'s features were carefully selected to be general enough so they won't become "legacy" in the foreseen future. – Yakov Galka Dec 13 '10 at 16:20
  • @ybungalobill: That's my point exactly. They're being overcautious. In making sure features won't become legacy in the foreseen future, the language itself will become legacy. – Zach Saw Jan 19 '11 at 06:32
  • 2
    I'm having a bit of trouble understanding this whole `using {}` thing. That's a feature idea, not a currently-valid C++ construct, right? @ZachSaw, why did you accept this answer if it's not what you're looking for? – Kyle Strand Mar 11 '15 at 18:27
  • @KyleStrand - It is a future idea, not a currently valid C++ construct, yes. If I might speak for Zack, I would say that he accepted it because it sparked the most interesting discussion in the comments and in combination with the comments explained how and why features get added to C++. – Omnifarious Oct 11 '17 at 05:32
1

You can use a typedef inside the class declaration to achieve the same

class Foo : public Bar
{
      typedef System::Network::Win32::Sockets::Handle Handle;
      typedef System::Network::Win32::Sockets::Error Error;

      void FooBar(Handle handle, Error& error);
};
Pang
  • 9,564
  • 146
  • 81
  • 122
Declan
  • 669
  • 1
  • 7
  • 12
  • 2
    In which case you'll end up typedef'ing all the types under `System::Network::Win32::Sockets` namespace used in the class. Not only that, you'll have to then typedef all the types under other namespaces used in that class too! You do realise that's not practical don't you? And in the CPP file, you'll still have to fully qualify the types. – Zach Saw Mar 05 '14 at 00:04
  • Your are of course correct. But thats not necessarily a bad thing. Usually one wont want (or shouldnt) to use a complete namespace anyways, but rather certain identifiers (eg Handle). And yes its a bit of a pain having to do the extra typing, just as it would be to write "using System::Network::Win32::Sockets::Handle" But that doesnt mean that one should prefer writing ""using System::Network::Win32::Sockets" just because its less typing. Its a trade off between fine grained control/clarity vs more text. – Declan Mar 05 '14 at 20:23
  • Correction : prefer writing ""using System::Network::Win32::Sockets" ..And in the .cpp file its generally ok to use the whole namespace (and avoid repeating the typedefs) since it wont be included in other headers and dirty the global namespace – Declan Mar 05 '14 at 20:28
  • Don't assume everything is about the programmer being lazy. Typing more is the least of my concerns. Typedefing so many types in each class makes the code extremely verbose. Readability suffers. – Zach Saw Mar 06 '14 at 00:40
  • Yes. And making everything in namespace "available" when you dont need it all is error prone and pollutes the current namespace. You only need to typedef the identifiers you need, which typically isnt that many. As I said its a compromise. More control with more text, or vice versa. – Declan Mar 09 '14 at 19:13
0

Maybe namespace alias?

namespace MyScope = System::Network::Win32::Sockets;
Omnifarious
  • 54,333
  • 19
  • 131
  • 194
-2

The obvious benefit of namespaces is that they allow you to avoid naming conflicts. However, by introducing an entire namespace into a class declaration, this benefit is voided. It's entirely possible that a function in the System namespace could conflict with your own Bar::MemberFunc function. You even note this in your sample code when you added the comment "no conflict with this".

You obviously don't want to introduce entire namespaces into your class like this:

using namespace System;
using namespace System::Network;
using namespace System::Network::Win32::Sockets;

And you can't add more narrowly scoped using statements like this into a class declaration. Putting these directly into a class declaration is illegal.

using System::Network::Win32::Sockets::Handle;
using System::Network::Win32::Sockets::Error;

What you can do is use the unnamed namespace. So, your header file would look something like this:

namespace {
    using System::Network::Win32::Sockets::Handle;
    using System::Network::Win32::Sockets::Error;
}

class Foo : public Bar
{
    using Bar::MemberFunc;

    // clean!
    void FooBar(Handle handle, Error& error /*, more declarations*/);
};

This has three distinct advantages.

  1. The contents of entire namespaces are not introduced. This helps to more easily avoid naming conflicts.
  2. You have a list, before your class declaration, of what your class depends upon to work correctly.
  3. Your function declarations are clean.

Please correct me if I'm wrong; I only briefly tested this. Quickly wrote up an example, and it compiled.

Ichimonji10
  • 344
  • 1
  • 3
  • 9
  • 2
    The anonymous namespace is local to a translation unit, not to a file. That means the names in the anonymous namespace are available to all the other files that are part of that translation units, even if they're other header files. That can silently change the meaning of random header files. – Omnifarious Dec 06 '10 at 05:47
  • 2
    Ambiguities could be solved as per usual, or via namespace alias. So your whole argument is moot. Also, your unnamed namespace is not scope restricted too - that's extremely bad. – Zach Saw Dec 06 '10 at 05:58