views:

382

answers:

5

I've done a bunch of Java coding recently and have got used to very specific package naming systems, with deep nesting e.g. com.company.project.db. This works fine in Java, AS3/Flex and C#. I've seen the same paradigm applied in C++ too, but I've also heard that it's bad to view C++ namespaces as direct counterparts to Java packages.

Is that true, and why? How are namespaces/packages alike and different? What problems are likely to be seen if you do use deep nested namespaces?

+4  A: 

Java packages are not nested, they're flat. Any apparent nesting is nothing more than a naming convention.

For example, the package com.company.project.db has no relation whatsoever to com.company.project or com.company.project.db.x. Code in com.company.project.db has no more access to code in com.company.project.db.x than would code in a.b.c.

skaffman
Interesting, I'd never thought about it but assumed package-level scope/visibility would apply to sub-packages. So a package level class in a.b.c is invisible to a.b.c.d?
John
BTW, Java enforces nesting in the file structure, doesn't it? Not what you meant, but still important... java packages are not arbitrary text you can type in (IIRC)
John
@John: On your first point: correct. On your second point, java tools generally enforce a directory structure that looks like the package naming, yes, but again, it's nothing more than a convention, albeit a strong one.
skaffman
True, but that doesn't answer the question...
sleske
@skaffman: are you sure that it is only a convention? I believe that is enforced not by the tools but by the language itself. If you write `import a.b.c.D;` the compiler will require that somewhere in the classpath there is a directory structure `a/b/c` where class `D` resides. And class `D` must be within the `a.b.c` package. Once enforced by the language it is no longer a convention but rather a requirement.
David Rodríguez - dribeas
@David: The language does not require that, the tools do. In that respect, it may as well be fixed, but it's important to make the distinction.
skaffman
@skaffman: I think I must disagree. To quote "The Java TMVirtual Machine Specification", 2.7.5 Fully Qualified Names: "The fully qualified name of a named package that is a subpackage of another named package consists of the fully qualified name of the containing package followed by "." followed by the simple (member) name of the subpackage." So the JVM spec *does* explicitly mention package name hierarchy.
sleske
[cont] On the other hand, the JVM says "Each Java virtual machine implementation determines how packages, compilation units, and subpackages are created and stored[...]" so the rule of putting class files into a directory hierarchy is just a convention of the ClassLoader which Sun's runtime implementation happens to use. OK, enough nitpicking :-).
sleske
+7  A: 

In C++ namespaces are just about partitioning the available names. Java packages are about modules. The naming hierarchy is just one aspect of it.

There's nothing wrong, per-se, with deeply nested namespaces in C++, except that they're not normally necessary as there's no module system behind them, and the extra layers just add noise. It's usually sufficient to have one or two levels of namespace, with the odd extra level for internal details (often just called Details).

There are also extra rules to C++ namespaces that may catch you out if overused - such as argument-dependent-lookup, and the rules around resolving to parent levels. WRT the latter, take:

namespace a{ namespace b{ int x; } }
namespace b{ string x; }
namespace a
{
  b::x = 42;
}

Is this legal? Is it obvious what's happening? You need to know the precendence of the namespace resolution to answer those questions.

Phil Nash
Interesting. Could you add some links about "dependent-lookup" and "resolving parent levels"? Never heard of it.
sleske
@sleske - there ya go
Phil Nash
@sleske: the full explanation is much longer than what you can actually write in a comment. The basic idea is what when the compiler finds a non-fully-qualified identifier it will try to match it starting in the current namespace, and if not found it will try the enclosing namespace... all the way to the root. This is extended by ADL (Argument Dependent Lookup), so that if you call a function on a set of arguments, it will also try to match the method identifier in the arguments namespaces. `f( std::string(), ::ns::myclass() )` will also look for `f` in `std` and `ns` namespaces.
David Rodríguez - dribeas
Thanks for the explanations. As for ADL: that seems mindbogglingly complicated. I wonder if that was really necessary in the language's design. I prefer the Java approach (either unqualified, or fully qualified). Well, C++ has never been excused of being too simple...
sleske
The original idea behind ADL was to let you use operators that had been overloaded within the namespace that the first operand lived. When it was noticed that this led to an enhanced interface principle (declare things that "operate" on other objects within the same namespace) it was extended to any function.There is a certain elegance to it, but at the same time it is subtle and often surprising (and used to be sporadically supported)
Phil Nash
A: 

You can have nested namespaces in C++.

They don't work the same as in java, though, obviously. Java packages are really much better defined and there is no real static init weirdness. With C++ namespaces are helpful but still have a fair bit of danger involved.

Charles Eli Cheese
Please clarify this "danger" you mention.
anon
+1  A: 

In C++, the basic unit of design and implementation is the class, not the namespace. Namespaces were intended as a means of preventing name clashes in large libraries, not for expressing concepts.

Classes have several advantages over namespaces:

  • they can have constructors and destructors
  • they can have private members
  • they cannot be re-opened

However, I would look twice at any deeply nested relationship. That is really not a good way of designing software, and leads to unreadable code, whether you juse classes or namespaces.

anon
I think you’re comparing the wrong units. Packages are much more like header files in C++ than like classes. The basic unit of modularity in C and C++ is header files and compilation units, not classes.
Konrad Rudolph
"they cannot be re-opened" - some would see that as a disadvantage ;-)
Phil Nash
@Konrad - I'd be careful about comparing header files with modules. Header files are very much a pre-processor thing. If anything the most closely corresponding entity we have right now is the translation unit (cpp file) - although the symbols *are* usually exported via header files - but that is not a necessity
Phil Nash
@Phil You are not suggesting C++ embraces duck typing, I hope!
anon
@Neil - where do you get that idea from?
Phil Nash
@Neil - oh, my "reopen classes" comment. I wasn't coming from the duck-typing angle (although it's a step in that direction) - just that it's often useful to be able to add to an existing class on an ad-hoc basis. I was dubious of the concept until I started using extension methods in C# and categories in Objective-C - both of which do it within a static-typing concept - and it leads to some neat solutions.
Phil Nash
@Neil... basic unit of design/OO is the class in all the other languages I mention too. In fact more so, since Java especially prevents procedural programming which C++ allows.
John
I don't think that class and namespaces are comparable entities at any level. Class is an OO concept, while namespace is a more general concept. You can have OO without namespaces, and you can have namespaces without OO. Namespaces (at least to me) are not just a name collision avoidance tool, but rather carry semantic information: they group related concepts together. The difference being that a class models an entity, and namespaces models groups of entities.
David Rodríguez - dribeas
I don't believe in the pure'OO paradigm, and in particular in 'utility classes' that synthetically bind stateless operations within a non-instantiable class... if they are completely stateless operations then they are better modeled with free functions, and grouping related operations into namespaces tells you that while they are free functions they are also related, and they relate to whatever the namespace name is (I am assuming that the namespace has a proper identifying name).
David Rodríguez - dribeas
@David I'm not sure they *carry* semantic information. They can be used to partition the namespace *along the lines of* groups of related concepts - but that's down to programmer discipline to maintain.
Phil Nash
@David - stateless classes are necessary in some cases, such as when you need a templated type for the whole "group"
Phil Nash
@Phil: I completely agree on the *carry* semantic information. I should have worded as 'it allows the programmer to group elements semantically' or something in that line. Then, on the 'stateless classes', well I was talking specifically about the concept of 'utility class' in OO, that refers to classes that just hold some utility functions together. There are cases where stateless classes make sense: traits for meta programming, and even in some cases a regular class can be stateless and still make sense as an entity, but those are not 'utility classes'.
David Rodríguez - dribeas
BTW, an example of utility class given in Wikipedia is the java Collections class, with only static methods in the line of `binarySearch`, `max`, `min`, `sort`... that are just algorithms applied to its arguments, and whose only relation is that they take 'collections' as arguments. In Java there are no free functions and you must rely in building utility classes to simulate free functions. In C++ you would have a namespace and a set of free (templated) functions.
David Rodríguez - dribeas
@ David - Agreed - Utility Class, as used here, is just a holder for what would be free functions, if available.
Phil Nash
A: 

I'll throw in a couple of things I've heard but don't know the truthfulness of, please help confirm/dispel them.

1)C++ performance is (somehow) affected by long fully-specified method names e.g namespace1::namespace2::namespace3::classX::method123()

2)You might hit a limit on allowed symbol length in the compiler/linker

John
1) No - namespaces are a purely compile-time thing. 2) Possible - but most C++ compilers support very long names - they have to, or templates wouldn't work.
anon
I'll back Neil up here on both counts and add that the symbol length limit is likely to be *per namespace*, rather for the whole qualified hierarchy.
Phil Nash
Even when you throw RTTI into the mix?
John
Do you mean that a type identifier you get from RTTI might be very long? Possible I suppose (the type id does not have to match the name the programmer provided), but very little C++ code uses this language feature.
anon