JAN
17
2004

Categorizing Classes without Namespaces or Packages

This time it started with a a thread on kde-core-devel:
I wrote about using classes for organizing functions and later wondered why I am using
static class methods - that's what C++ has namespaces for. I think the answer lies somewhere
between the way I am using namespaces and the way tools like Doxygen organize
the documentation. I am using namespaces in a Java-package-like way. They are a
coarse categorization for classes, with 5-50 classes per namespace. That's what I
am used to from Java, and it makes a lot of sense for classes. It would be possible
to collect functions in namespaces instead of classes, but then you would have to
browse through both the classes and the namespaces in Doxygen-generated documentation.
Having two kinds of categorization is just too much, it makes documentation too hard to read and code too hard to find.



The C++ syntax does not really help you with organizing your code or reading other people's code,
especially if you are not using an IDE. It's hard to find out in which file a symbol
is declared, and even more difficult to find out where it is implemented. Functions and
global variables are the worst, unlike classes they usually do not
have their own header. Avoiding these problems requires quite a lot of discipline,
you need to keep a consistent naming scheme for all files. This does not help
when you work with someone else's sources though. Another part of C++ that I don't
like is the separation of declarations/headers and implementation. I hate typing more
than necessary, syncing headers with the implementation can be annoying and the
stupid #ifdef protectors that you need to write in every header are just braindead.



Two features in Java that work really well are packages and the source
file layout. When you have a class My.Library.Helper you are required to
write both implementation and declaration into a file My/Library/Helper.java. This
makes it easy to locate the implementation. As everything in Java is
in a class there are no problems with locating functions. They are static methods
and can only be invoked by specifying the class name (e.g. Math.round()). This
is annoying to type, but makes reading someone else's source code much easier.
Unfortunately Sun recommends to use a reverse DNS name as package name, and when you
follow it you will have to hide your source code somewhere in a deep directory hierarchy. Unless you are writing a library I would suggest you to ignore Sun's advice and use a short one-step package name.

Java 1.5 shows that Sun recently got hit by a healthy dose of reality, and one of the
results are 'static imports'. If you declare static import java.lang.Math; you do not
need to write Math.cos() any longer, you can just write cos(). This makes it a little
bit more difficult to find the method's declaration (you need to look out for static imports),
but I can understand Sun's decision. The lack of static imports caused people to do
strange things, many people inherited from classes that contained useful static methods
only to avoid writing the class prefix for every invocation... it's a nice compromise between
the ease of use of C++'s uncategorized function, and Java's "everything is a class method"'
principle.



To make it short, I would choose Java's package system over C++'s header/namespace system
any time. But when I thought about it I came to an interesting question: why does Java
differentiate between packages and classes? A class with the full path My.Library.Helper could be a class Helper in the package My.Library, or a class
Library.Helper in the package My. Inner/sub classes and packages use the
same naming scheme, they are identical for the API's user, so why should there be a
difference in the declaration? Isn't is possible to have only one?



I think that with a few tweaks you can get rid of the package mechanism and make everything
a class. There are three small problems to be solved: The first problem is how to
define a class My.Library.Helper. The traditional Java syntax would be

class My {
	class Library {
		class Helper {
		}
	}
}

But that would be annoying to type (even if not annoying enough to stop the C++ guys
to use a similar syntax for namespaces..). So just do the obvious and
create an alternative syntax that lets the developer specify the full class name, like
C# does:

class My.Library.Helper {
}

Problem one solved.

The second issue is that Java allows only one "class Name {}" declaration to
specify a class. You can't do this when the class mechanism is also used for
categorization purposes, as you don't want to specify all sub-classes in a single file.
Thus you need to allow more than one declaration for a class, and the
compiler needs to merge them like C#'s 'partial' class attribute does. This requires that the
source file naming scheme needs to be changed: a class with the name My.Library.Helper
can be defined in all files that have either the name My/Library/Helper.java or
My/Library/Helper/*.java. If a class is a regular class a developer will choose the former scheme. When the class is used like a package, containing only sub-classes, the latter file scheme is used. In some cases it may also make sense to have both. Both schemes allow
developer and compiler to easily find all declarations of a class, and certainly not more
difficult than with Java's current package/inner-class mix. Problem two solved.

Problem three are imports. So far Java allowed you to import either a single class
('import My.Library.Helper') or to import a whole package ('import My.Library.*').
Exactly the same syntax can be kept for sub-classes. A simple name imports a single
class, an appended '*' imports all sub-classes. Problem three solved.



To make it short, there should be no need for packages or namespaces. With a few small changes in the language the class is sufficient as a single way of organizing methods, variables and other classes.