Ada 95 Quality and Style Guide Chapter 3

Chapter 3: Readability - TOC - 3.3 COMMENTS

3.3.5 Data Comments


  • Comment on all data types, objects, and exceptions unless their names are self-explanatory.
  • Include information on the semantic structure of complex, pointer-based data structures.
  • Include information about relationships that are maintained between data objects.
  • Omit comments that merely repeat the information in the name.
  • Include information on redispatching for tagged types in cases where you intend the specializations (i.e., derived types) to override these redispatching operations.

  • example

    Objects can be grouped by purpose and commented as:

    -- Current position of the cursor in the currently selected text
    -- buffer, and the most recent position explicitly marked by the
    -- user.
    -- Note:  It is necessary to maintain both current and desired
    --        column positions because the cursor cannot always be
    --        displayed in the desired position when moving between
    --        lines of different lengths.
    Desired_Column : Column_Counter;
    Current_Column : Column_Counter;
    Current_Row    : Row_Counter;
    Marked_Column  : Column_Counter;
    Marked_Row     : Row_Counter;

    The conditions under which an exception is raised should be commented:

    -- Exceptions
    Node_Already_Defined : exception;   -- Raised when an attempt is made
                                        --|   to define a node with an
                                        --|   identifier which already
                                        --|   defines a node.
    Node_Not_Defined     : exception;   -- Raised when a reference is
                                        --|   made to a node which has
                                        --|   not been defined.

    Here is a more complex example, involving multiple record and access types that are used to form a complex data structure:

    -- These data structures are used to store the graph during the
    -- layout process. The overall organization is a sorted list of
    -- "ranks," each containing a sorted list of nodes, each containing
    -- a list of incoming arcs and a list of outgoing arcs.
    -- The lists are doubly linked to support forward and backward
    -- passes for sorting. Arc lists do not need to be doubly linked
    -- because order of arcs is irrelevant.
    -- The nodes and arcs are doubly linked to each other to support
    -- efficient lookup of all arcs to/from a node, as well as efficient
    -- lookup of the source/target node of an arc.
    type Arc;
    type Arc_Pointer is access Arc;
    type Node;
    type Node_Pointer is access Node;
    type Node is
          Id       : Node_Pointer;-- Unique node ID supplied by the user.
          Arc_In   : Arc_Pointer;
          Arc_Out  : Arc_Pointer;
          Next     : Node_Pointer;
          Previous : Node_Pointer;
       end record;
    type Arc is
          ID     : Arc_ID;        -- Unique arc ID supplied by the user.
          Source : Node_Pointer;
          Target : Node_Pointer;
          Next   : Arc_Pointer;
       end record;
    type Rank;
    type Rank_Pointer is access Rank;
    type Rank is
          Number     : Level_ID;  -- Computed ordinal number of the rank.
          First_Node : Node_Pointer;
          Last_Node  : Node_Pointer;
          Next       : Rank_Pointer;
          Previous   : Rank_Pointer;
       end record;
    First_Rank : Rank_Pointer;
    Last_Rank  : Rank_Pointer;


    It is very useful to add comments explaining the purpose, structure, and semantics of the data structures. Many maintainers look at the data structures first when trying to understand the implementation of a unit. Understanding the data that can be stored, along with the relationships between the different data items and the flow of data through the unit, is an important first step in understanding the details of the unit.

    In the first example above, the names Current_Column and Current_Row are relatively self-explanatory. The name Desired_Column is also well chosen, but it leaves the reader wondering what the relationship is between the current column and the desired column. The comment explains the reason for having both.

    Another advantage of commenting on the data declarations is that the single set of comments on a declaration can replace multiple sets of comments that might otherwise be needed at various places in the code where the data is manipulated. In the first example above, the comment briefly expands on the meaning of "current" and "marked." It states that the "current" position is the location of the cursor, the "current" position is in the current buffer, and the "marked" position was marked by the user. This comment, along with the mnemonic names of the variables, greatly reduces the need for comments at individual statements throughout the code.

    It is important to document the full meaning of exceptions and under what conditions they can be raised, as shown in the second example above, especially when the exceptions are declared in a package specification. The reader has no other way to find out the exact meaning of the exception (without reading the code in the package body).

    Grouping all the exceptions together, as shown in the second example, can provide the reader with the effect of a "glossary" of special conditions. This is useful when many different subprograms in the package can raise the same exceptions. For a package in which each exception can be raised by only one subprogram, it may be better to group related subprograms and exceptions together.

    When commenting exceptions, it is better to describe the exception's meaning in general terms than to list all the subprograms that can cause the exception to be raised; such a list is harder to maintain. When a new routine is added, it is likely that these lists will not be updated. Also, this information is already present in the comments describing the subprograms, where all exceptions that can be raised by the subprogram should be listed. Lists of exceptions by subprogram are more useful and easier to maintain than lists of subprograms by exception.

    In the third example, the names of the record fields are short and mnemonic, but they are not completely self-explanatory. This is often the case with complex data structures involving access types. There is no way to choose the record and field names so that they completely explain the overall organization of the records and pointers into a nested set of sorted lists. The comments shown are useful in this case. Without them, the reader would not know which lists are sorted, which lists are doubly linked, or why. The comments express the intent of the author with respect to this complex data structure. The maintainer still has to read the code if he wants to be sure that the double links are all properly maintained. Keeping this in mind when reading the code makes it much easier for the maintainer to find a bug where one pointer is updated and the opposite one is not.

    See Guideline 9.3.1 for the rationale for documenting the use of redispatching operations. (Redispatching means converting an argument of one primitive operation to a class-wide type and making a dispatching call to another primitive operation.) The rationale in Guideline 9.3.1 discusses whether such documentation should be in the specification or the body.

    < Previous Page Search Contents Index Next Page >
    1 2 3 4 5 6 7 8 9 10 11
    Appendix References Bibliography