JavaPLT coding conventions

Originally written 6/18/2001 by Brian Stoler, as adapted from past experience at Oracle and elsewhere. Updated 1/22/2003 by Eric Allen and 1/14/2005, 1/9/2007 by Corky Cartwright.

Our conventions follow the Sun Java coding conventions with the following exceptions and clarifications:

Packages

Java classes should be packaged as a subpackage of edu.rice.cs, to prevent name clashes. Each major project should have one top-level package under edu.rice.cs, and then large subcomponents of each should form subpackages under each. Current package names:

When we incorporated DynamicJava as part of our code base, we retained its package names (beginning with koala. We may move it into the edu.rice.cs package hierarchy at a later date.

Subversion

All source should be maintained in Subversion (svn) using our ant scripts which force code to compile and pass all unit tests before it can be checked into the Subversion database. Remember to perform svn add operations for every file that you add to the database.

README

All packages should have a text file named README describing, at least, the purpose of the package.

Class layout

The elements of a class should be laid out in the following order:
  1. Constants (i.e., static final fields).
  2. Static fields.
  3. All other fields that do not contain instances of anonymous inner classes.
  4. Fields containing instances of anonymous inner classes.
  5. Public static methods and constructors.
  6. Public methods.
  7. Protected methods
  8. Private and package private methods. Due to our use of JUnit, it is often necessary to increase method visibility from private to package private, so we tend to use the two interchangeably.

Documentation

Every non-trivial public or protected method should have an associated javadoc comment. Trivial methods include naive getter methods and little else. Inside a method, use extra comments to explain unusual behavior, or behavior that relies on non-local state (i.e., state outside of the method). Write comments to explain why your code does what it does, rather than simply rewriting the code in English.

Comment Formatting

Try not to waste vertical space unless it is important for clarity. For example, when writing a block comment (/* ... */) or a javadoc comment, do not open the comment with an isolated /* or /**; use the remainder of the space on that line the first line of text. In many cases, the comment will fit on a single line. For example, write

  /* Here is a comment */
  
rather than
  /*
   * Here is a block comment.
   */
  

For a multi-line javadoc comment, write

  /** This javadoc comment
    * spans multiple lines.
    */
  
rather than
  /** 
   * This javadoc comment
   * spans multiple lines.
   */
  
The DrJava indenting rules understand this style and lines up leading asterisks on lines after the first with the second asterisk on the opening line.

Indentation

Indentation is two space characters. Tab characters should NEVER be used. This ensures that source files will look right no matter which editor someone uses. Similarly, lines should never span more than 120 characters. We used to enforce an 80 character limit, but with increasing screen sizes this limit seemed anachronistic. Lines should fit on a machine running DrJava in the full screen of a 1024x768 display. Most lines should be short and indentation levels should be modest.

Line Splitting

When an expression does not fit on a single line, it should be split in a way consistent with the abstract syntax tree for the expression. We disagree with the Sun coding standard's directive to place an infix binary operator at the beginning of a new line; we prefer to see it at the end of the previous line. The key issue here is a presentation that is consistent with the precedence of operators. The decomposition implied by line splitting should be consistent with the grouping determined by the parsing rules for expressions.

Braces

The opening brace goes at the end of the first line of a new block, as opposed to the beginning of the subsequent line. The only exceptions are when the opening of the block spans more than one line, e.g., a class that implements more interfaces that can fit on one line, or when a method has a very long signature.

Conditional and loop bodies should always use braces, unless the body can fit on the same line as the header.

Also, else, if/else and catch/finally should begin on their own line.

Example conditional:

    if (test) {
      ...
    }
    else if (test2) {
      ...
    }
    else {
      ...
    }
    

Example try/catch/finally:

    try {
      ...
    }
    catch (Exception e) {
      ...
    }
    finally {
      ...
    }
    

If a catch or finally body fits on one line, the enclosing braces may be placed on the same line.

Mutation in expressions

Unless it is unavoidable (which it usually is not) or would terribly reduce code readability, do not change any state in an expression. This includes conditional or loop test expressions. All mutations should be written as their own statements. If you change state in an expression, explain what's going on and why in comments. For example:

      l = l.rest();
      f = l.first();
    
is preferable to:
     f = l.pop().first();
   

Variable naming conventions

Ternary (?) operator

Expressions using the ternary operator should be avoided unless they are very succinct. In most cases, they are confusing, and furthermore in Java it does not generate any better code than the corresponding if statement.

JUnit: Don't use the assert() method!

Since Java 1.4, assert has been a keyword. Thus, compiling code that uses this function (as was previously used in JUnit) will fail. Thus, JUnit renamed its functions to assertTrue().

Never catch and do nothing!

As a matter of principle, never leave a catch clause empty, except perhaps in unit tests. It's irrelevant whether you can prove that the catch clause is unreachable. Your proof will undoubtably rely on the correctness of the rest of the code (including the code in the try clause), which is never a given. If you are nonetheless certain that the clause will never be reached, throw an UnexpectedException in it. The UnexpectedException class is defined in the package edu.rice.cs.util; it should have been included by the Java designers in java.lang. Do not throw a RuntimeException; in constrast to an UnexpectedException, it does not propogate the underlying exception that was caught. Even if this helps to catch only one bug in a hundred, the time it takes will more than pay for itself.

The only significant exception to this rule is a test case that specifically checks that an exception is properly thrown. In essentially all other test cases, it is wrong sin to catch an exception and do nothing. In most situations, test cases should not include try-catch blocks. Instead, they should simply throw exceptions to the caller.