[Ada Information Clearinghouse]
Ada '83 Quality and Style:
Guidelines for Professional Programmers
Copyright 1989, 1991,1992
Software Productivity Consortium, Inc., Herndon, Virginia.
CHAPTER 3: Readability
Choose names that clarify the object's or entity's intended use. Ada allows
identifiers to be any length as long as the identifier fits on a line with all
characters being significant (including underscores). Identifiers are the
names used for variables, constants, program units, and other entities within
a program.
Language Ref Manual references:
2.3 Identifiers,
4.1 Universal Expressions
guideline
- Choose names that are as self-documenting as possible.
- Use a short synonym instead of an abbreviation (see Guideline 3.1.4).
- Use names given by the application but not obscure jargon.
example
In a tree-walker, using the name
Left instead of
Left_Branch is sufficient to
convey the full meaning given the context. However, use
Time_Of_Day instead
of
TOD.
Mathematical formulas are often given using single-letter names for variables.
Continue this convention for mathematical equations where it would recall the
formula; for example:
A*(X**2) + B*C.
rationale
A program that follows these guidelines can be more easily comprehended.
Self-documenting names require fewer explanatory comments. Empirical studies
have shown that you can further improve comprehension if your variable names
are not excessively long (Schneiderman 1986, 7). The context and application
can help greatly. The unit of measure for numeric entities can be a source of
type names.
note
See
Guideline 8.1.2 for a discussion on how to use the application domain as a
guideline for selecting abbreviations.
Language Ref Manual references:
3.1 Declarations
guideline
- Use singular, general nouns as (sub)type identifiers.
- Choose identifiers that describe one of the (sub)type's values.
- Do not use identifier constructions (e.g., suffixes) that are unique
to (sub)type identifiers.
- Do not use the type names from predefined packages.
example
type Day is
(Monday, Tuesday, Wednesday, Thursday, Friday,
Saturday, Sunday);
type Day_Of_Month is range 0 .. 31;
type Month_Number is range 1 .. 12;
type Historical_Year is range -6_000 .. 2_500;
type Date is
record
Day : Day_Of_Month;
Month : Month_Number;
Year : Historical_Year;
end record;
In particular, Day should be used in preference to Days or Day_Type;
The identifier Historical_Year might appear to be specific, but it is actually
general, with the adjective, historical, describing the range constraint.
rationale
When this style and the suggested style for object identifiers are used,
program code more closely resembles English (see
Guideline 3.2.3).
Furthermore, this style is consistent with the names of the language's
predefined identifiers. They are not named
Integers,
Booleans,
Integer_Type,
or
Boolean_Type.
However, using the name of a type from the predefined packages is sure to
confuse a programmer when that type appears somewhere without a package
qualification.
Language Ref Manual references:
3.3 Types and Subtypes,
8.6 The Package Standard,
14.3.10 Specification of the Package Text_IO
guideline
- Use predicate clauses or adjectives for boolean objects.
- Use singular, specific nouns as object identifiers.
- Choose identifiers that describe the object's value during execution.
- Use singular, general nouns as identifiers for record components.
example
Nonboolean objects:
Today : Day;
Yesterday : Day;
Retirement_Date : Date;
Boolean objects:
User_Is_Available : Boolean; -- predicate clause
List_Is_Empty : Boolean; -- predicate clause
Empty : Boolean; -- adjective
Bright : Boolean; -- adjective
rationale
Using specific nouns for objects establishes a context for understanding the
object's value, which is one of the general values described by the
(sub)type's name (
Guideline 3.2.2). Object declarations become very
English-like with this style. For example, the first declaration above is
read as "Today is a Day."
General nouns, rather that specific, are used for record components because a
record object's name will supply the context for understanding the component.
Thus, the following component is understood as "the year of retirement.":
Retirement_Date.Year
Following conventions which relate object types and parts of speech makes code
read more like text. For example, because of the names chosen, the following
code segment needs no comments:
if List_Is_Empty then
Number_Of_Elements := 0;
else
Number_Of_Elements := Length_Of_List;
end if;
note
If it is difficult to find a specific noun that describes an object's value
during the entire execution of a program, the object is probably serving
multiple purposes. Multiple objects should be used in such a case.
Language Ref Manual references:
3.2 Objects and Named Numbers,
3.5.3 Boolean Types
guideline
- Use action verbs for procedures and entries.
- Use predicate-clauses for boolean functions.
- Use nouns for nonboolean functions.
- Give packages names that imply higher levels of organization than
subprograms. Generally, these are noun phrases that describe the abstraction
provided.
- Give tasks names that imply an active entity.
- Name generic subprograms as if they were nongeneric subprograms.
- Name generic packages as if they were nongeneric packages.
- Make the generic names more general than the instantiated names.
example
The following are sample names for elements that comprise an Ada program.
Sample procedure names:
procedure Get_Next_Token -- get is a transitive verb
procedure Create -- create is a transitverb
Sample function names for boolean-valued functions:
function Is_Last_Item -- predicate clause
function Is_Empty -- predicate clause
Sample function names for nonboolean-valued functions:
function Successor -- common noun
function Length -- attribute
function Top -- component
Sample package names:
package Terminal is -- common noun
package Text_Utilities is -- common noun
Sample task names:
task Terminal_Resource_Manager is -- common noun that shows action
Below is a sample piece of code to show the clarity that results from using
these conventions the parts-of-speech naming conventions.
Get_Next_Token(Current_Token);
case Current_Token is
when Identifier => Process_Identifier;
when Numeric => Process_Numeric;
end case; -- Current_Token
if Is_Empty(Current_List) then
Number_Of_Elements := 0;
else
Number_Of_Elements := Length(Current_List);
end if;
When packages and their subprograms are named together, the resulting code is
very descriptive.
if Stack.Is_Empty(Current_List) then
Current_Token := Stack.Top(Current_List);
end if;
rationale
Using these naming conventions creates understandable code that reads much
like natural language. When verbs are used for actions, such as subprograms,
and nouns are used for objects, such as the data that the subprogram
manipulates, code is easier to read and understand. This models a medium of
communication already familiar to a reader. Where the pieces of a program
model a real-life situation, using these conventions reduces the number of
translation steps involved in reading and understanding the program. In a
sense, your choice of names reflects the level of abstraction from computer
hardware toward application requirements.
note
There are some conflicting conventions in current use for task entries. Some
programmers and designers advocate naming task entries with the same
conventions used for subprograms to blur the fact that a task is involved.
Their reasoning is that if the task is reimplemented as a package, or vice
versa, the names need not change. Others prefer to make the fact of a task
entry as explicit as possible to ensure that the existence of a task with its
presumed overhead is recognizable. Project-specific priorities may be useful in
choosing between these conventions.
Language Ref Manual references:
6.1 Subprogram Declarations,
6.5 Function Subprograms,
7.2 Package Specifications and Declarations,
9.1 Abort Statements,
9.5 Entries, Entry Calls, and Accept Statements,
12.1 Generic Declarations,
12.3 Generic Instantiation
guideline
- Use symbolic values instead of literals wherever possible.
- Use constants instead of variables for constant values.
- Use named numbers instead of constants when possible.
- Use named numbers to replace numeric literals whose type or context is truly universal.
- Use constants for objects whose values cannot change after elaboration
(United Technologies 1987).
- Show relationships between symbolic values by defining them with
static expressions.
- Use linearly independent sets of literals.
- Use attributes like 'First and 'Last instead of literals wherever
possible.
example
3.141_592_653_589_793 -- literal
Max : constant Integer := 65_535; -- constant
Pi : constant := 3.141_592; -- named number
PI / 2 -- static expression
PI -- symbolic value
Declaring Pi as a named number allows it to be referenced symbolically in the
assignment statement below:
Area := Pi * Radius**2; -- if radius is known.
instead of
Area := 3.141_59 * Radius**2; -- Needs explanatory comment.
Also, ASCII.Bel is more expressive than Character'Val(8#007#).
Clarity of constant and named number declarations can be improved by using
other constant and named numbers. For example:
Bytes_Per_Page : constant := 512;
Pages_Per_Buffer : constant := 10;
Buffer_Size : constant := Pages_Per_Buffer * Bytes_Per_Page;
is more self-explanatory and easier to maintain than
Buffer_Size : constant := 5_120; -- ten pages
The following literals should be constants:
if New_Character = '$' then -- "constant" that may change
...
if Current_Column = 7 then -- "constant" that may change
rationale
Using identifiers instead of literals makes the purpose of expressions clear
reducing the need for comments. Constant declarations consisting of
expressions of numeric literals are safer since they do not need to be
computed by hand. They are also more enlightening than a single numeric
literal since there is more opportunity for embedding explanatory names.
Clarity of constant declarations can be improved further by using other
related constants in static expressions defining new constants. This is not
less efficient because static expressions of named numbers are computed at
compile time.
A constant has a type. A named number can only be a universal type: universal
integer or universal real. Strong typing is enforced for identifiers but not
literals. Named numbers allow compilers to generate more efficient code than
for constants and to perform more complete error checking at compile time. If
the literal contains a large number of digits (as Pi in the example above),
the use of an identifier reduces keystroke errors. If keystroke errors occur,
they are easier to locate either by inspection or at compile time.
Linear independence of literals means that the few literals that are used do
not depend on one another and that any relationship between constant or named
values is shown in the static expressions. Linear independence of literal
values gives the property that if one literal value changes, all of the named
numbers of values dependent on that literal are automatically changed.
note
There are some gray areas where the literal is actually more self-documenting
than a name. These are application-specific and generally occur with
universally familiar, unchangeable values such as the following relationship:
Fahrenheit := 32.0 + (9.0 * Celsius) / 5.0;
Language Ref Manual references:
2.4 Numeric Literals,
2.5 Character Literals,
2.6 String Literals,
3.2 Objects and Named Numbers,
4.9 Static Expressions and Static Subtypes,
A. Predefined Language Attributes
Back to document index