Contents:
This handout describes how to document the specifications of classes and methods. This document focuses on practical issues.
This document uses the Line class as an example. Notice that we do not provide fields or method bodies in our example. This document covers specifying the behavior of classes and methods (what they should do), not their implementation (what they actually do and how they do it). Abstraction Functions and Representation Invariants covers how to document a class's implementation.
/** * This class represents the mathematical concept of a line segment. * * Abstract Invariant: * A line's start-point must be different from its end-point. */ public class Line { ... // Fields not shown. /** * @requires p != null && ! p.equals(start-point) * @modifies this * @effects Sets end-point to p */ public void setEndPoint(Point p) { ... } ... }
Because the concepts discussed here are interrelated, it is best to start with a short list of definitions of before diving into the details.
The above concepts are included in a class's external specification (in Javadoc). They aid a client with using the class.
The rest of this document is organized as follows. First, it explains how to document what a class abstractly represents using abstract state.Then, it explains how to specify method behavior, in terms of abstract state.
To a computer, an instance of an object is a series of zeros and ones. To humans, on the other hand, these zeros and ones represent higher-level abstract ideas: integers, strings, lines, and lists, for example. The abstract value of an object is what the object represents to humans on this abstract level.
The abstract state of an object is what information a humans associate with the abstract value of an object. An abstract value is determined by the abstract state. For example, for the String "cat", humans associate the following sequence of letters: 'c', 'a', and 't'. This sequence of letters is the abstract state of the String.
It is important to note that how the String "cat" is represented concretely (within the Java code) does not affect its abstract state. Whether String internally uses an array, a List or some clever compressed numerical encoding for the the characters 'c', 'a', and 't', the abstract state of "cat" is still a just a sequence of those letters.
For some data types (classes), the abstract value space consists of familiar mathematical objects:
If so, you're in luck. You can use conventional notation for explaining the class's abstract values and functions on its abstract value (see later sections).
You aren't obliged to use this syntax. Some of it is more standard than the rest: everybody with some training in mathematics recognizes set comprehension syntax, but sequence concatenation isn't particularly standardized. You may find it clearer to write sequence concatenation as a function like concat(x, y). What really matters is clarity and lack of ambiguity, so if you have any doubt whether your reader will understand you, just define it: "...where concat(x,y) is the concatenation of two sequences x and y."
Method specifications describe the behavior of a method in terms of its preconditions and postconditions. Note that method specifications may only refer to specification fields, method arguments, and global variables (aka public static fields), never to the concrete fields of the implementation.
Preconditions are properties that must be true when the method is called. It is the responsibility of the caller to guarantee that these properties hold. If the preconditions do not hold, the method is allowed to behave in absolutely any fashion, including crashing the program, continuing with incorrect results, informing the user of the problem, or gracefully recovering from the problem. Callers should always assume that preconditions are not checked by a method. However, it is good practice — though not required — for a method to check its preconditions (if the check can be performed efficiently) and throw an error if they are not satisfied.
Preconditions are indicated by the "requires" clause in a method specification. If a "requires" clause is omitted from the method specification, it is assumed that the method does not have any preconditions.
Postconditions are properties that a method guarantees will hold when the method exits. However, if the precondition did not hold when the method was called, then all bets are off, and the method may behave in any fashion whatsoever. In particular, if the precondition does not hold upon method entry, then the postcondition need not hold on method exit.
A postcondition can be written as a single complex logical formula, but it is convenient to separate it into logically distinct parts. CSE 331 uses "return", "effects", "throws", and "modifies". (In the descriptions below, "default" indicates what is assumed if that clause is omitted from the method specification.)
A subclass often has a different (stronger) specification than its superclass, and often has a larger abstract state than its superclass. When the specification and abstract state are identical to those of the parent (for instance, an implementation of an abstract class), then there is no need to repeat them in the subclass. However, it is helpful to include a brief note indicating that the superclass documentation should be used instead. That note helps readers to distinguish whether the specification is the same, or the author simply didn't document the class.
When the specifications differ, then you have two options. The first option is to repeat, in the subclass, the full superclass documentation. The advantage is that everything is in one place, which may improve understanding. The second option is to augment the existing specification -- for example, to add a few new specification fields and constraints on them. Whichever you do, make sure that you clearly indicate your approach, and that you are consistent throughout the codebase.
Similar rules hold for a method that overrides another method. It's acceptable to leave the Javadoc blank if the specification is identical. (The generated HTML will use the overridden method's Javadoc documentation, but a normal Java comment is a good hint to someone who is reading the source code.) Otherwise, it is usually better to give the complete specification. If you merely augment the overridden method's specification, be sure to refer to it in the documentation.