Categorizing Classes without Namespaces or Packages

    tjansen's picture
    2004
    17
    Jan

    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.