fundamentals
In programs or components intended to have a long life, avoid
using the features of Ada declared as "obsolescent"
by Annex J of the Ada Reference Manual (1995), unless the use
of the feature is needed for backward compatibility with Ada 83
(Ada Reference Manual 1983).
Document the use of any obsolescent features.
Avoid using the following features:
- - The short renamings of the packages in the predefined environment
(e.g., Text_IO as opposed to Ada.Text_IO)
- - The character replacements of ! for |, :
for #, and % for quotation marks
- - Reduced accuracy subtypes of floating-point types
- - The 'Constrained attribute as applied to private types
- - The predefined package ASCII
- - The exception Numeric_Error
- - Various representation specifications, including at
clauses, mod clauses, interrupt entries, and the Storage_Size
attribute
Make informed assumptions about the support provided for the
following on potential target platforms:
- - Number of bits available for type Integer
(range constraints)
- - Number of decimal digits of precision available for floating-point types
- - Number of bits available for fixed-point types (delta and range constraints)
- - Number of characters per line of source text
- - Number of bits for Root_Integer expressions
- - Number of seconds for the range of Duration
- - Number of milliseconds for Duration'Small
- - Minimum and maximum scale for decimal types
Avoid assumptions about the values and the number of values
included in the type Character.
Use highlighting comments for
each package, subprogram, and task where any nonportable
features are present.
For each nonportable feature employed, describe the expectations
for that feature.
Consider using only a parameterless procedure as the main subprogram.
Consider using Ada.Command_Line for accessing values
from the environment, but recognize that this package's behavior
and even its specification are nonportable.
Encapsulate and document all uses of package Ada.Command_Line.
Create packages specifically designed to isolate hardware and
implementation dependencies and designed so that their specification will not change when porting.
Clearly indicate
the objectives if machine or solution efficiency is the reason
for hardware or implementation-dependent code.
For the packages that hide implementation dependencies, maintain
different package bodies
for different target environments.
Isolate interrupt receiving
tasks into implementation-dependent
packages.
Refer to Annex M of the Ada Reference Manual (1995) for a list
of implementation-dependent features.
Avoid the use of vendor-supplied packages.
Avoid the use of features added to the predefined packages that are not specified in the Ada language definition
or Specialized Needs Annexes.
Use features defined in the Specialized Needs Annexes rather
than vendor-defined features.
Document clearly the use of any features from the Specialized
Needs Annexes (systems programming, real-time systems, distributed
systems, information systems, numerics, and safety and security).
Do not write code whose correct execution depends on the particular
parameter passing mechanism used by an implementation (Ada Reference
Manual 1995, §6.2; Cohen 1986).
If a subprogram has more than one formal parameter of a given
subtype, at least one of which is [in] out, make sure
that the subprogram can properly handle the case when both formal
parameters denote the same actual object.
Avoid depending on the order in which certain constructs in
Ada are evaluated .
numeric types and expressions
Avoid using the predefined numeric types in package Standard .
Use range and digits declarations and let the implementation pick the appropriate representation.
For programs that require greater accuracy than that provided by the global assumptions, define a package
that declares a private type
and operations as needed; see Pappas (1985) for a full explanation
and examples.
Consider using predefined numeric types (Integer, Natural,
Positive) for:
- - Indexes into arrays where the index type is not significant,
such as type String
- - "Pure" numbers, that is, numbers with no associated
physical unit (e.g., exponents)
- - Values whose purpose is to control a repeat or iteration count
Use an implementation that supports the Numerics Annex (Ada Reference Manual 1995, Annex G) when performance and accuracy
are overriding concerns .
Carefully analyze what accuracy and precision you really need.
Do not press the accuracy limits of the machine(s).
Comment the analysis
and derivation of the numerical aspects of a program.
Anticipate the range of values of subexpressions to avoid exceeding
the underlying range of their base type. Use derived types, subtypes,
factoring, and range constraints on numeric types.
Consider using <= and >= to do relational
tests on real valued arguments, avoiding the <, >,
=, and /= operations.
Use values of type attributes
in comparisons and checking for small values.
In information systems, declare different numeric decimal types
to correspond to different scales (Brosgol, Eachus, and Emery
1994).
Create objects of different decimal types to reflect different
units of measure (Brosgol, Eachus, and Emery 1994).
Declare subtypes of the appropriately scaled decimal type to
provide appropriate range constraints for application-specific
types.
Encapsulate each measure category in a package (Brosgol, Eachus,
and Emery 1994).
Declare as few decimal types as possible for unitless data (Brosgol,
Eachus, and Emery 1994).
For decimal calculations, determine whether the result should
be truncated toward 0 or rounded.
Avoid decimal types and arithmetic on compilers that do not
support the Information Systems Annex (Ada Reference Manual 1995, Annex F) in full.
storage control
Do not use a representation clause to specify number of storage
units.
Do not compare access-to-subprogram values.
Consider using explicitly defined storage pool mechanisms.
tasking
Do not depend on the order in which task objects are activated
when declared in the same declarative list.
Do not depend on a particular delay being achievable (Nissen
and Wallis 1984).
Never use knowledge of the execution pattern of tasks to achieve timing requirements.
Do not assume a correlation between System.Tick and
type Duration.
Do not depend on the order in which guard conditions are evaluated or on the algorithm for choosing among
several open select alternatives.
Do not assume that tasks execute uninterrupted until they reach a synchronization point.
Use pragma Priority
to distinguish general levels of importance only.
Avoid using the abort statement.
Do not use unprotected shared variables.
Consider using protected types to provide data synchronization.
Have tasks communicate
through the rendezvous mechanism.
Do not use unprotected shared variables as a task synchronization device.
Consider using protected objects to encapsulate shared data.
Use pragma Atomic or Volatile only
when you are forced to by run-time system deficiencies.
exceptions
Do not depend on the exact locations at which predefined exceptions
are raised.
Do not rely on the behavior of Ada.Exceptions beyond
the minimum defined in the language.
Do not raise implementation-specific exceptions.
Convert implementation-specific exceptions within interface packages to visible
user-defined exceptions.
representation clauses and implementation-dependent features
Use algorithms that do not depend
on the representation of the data and,
therefore, do not need representation clauses.
Consider using representation clauses when accessing or defining
interface data or when a specific representation is needed to
implement a design .
Do not assume that sharing source files between programs guarantees
the same representation of data types in those files.
Avoid using package System constants except in attempting
to generalize other machine-dependent constructs.
Avoid machine code inserts.
Use the package Interfaces and its language-defined
child packages rather than implementation-specific mechanisms.
Consider using pragma Import rather than access-to-subprogram
types for interfacing to subprograms in other languages.
Isolate all subprograms employing pragmas Import, Export,
and Convention
to implementation-specific (interface) package bodies.
Avoid pragmas and attributes added by the compiler implementor.
Avoid dependence on Ada.Unchecked_Deallocation.
Avoid dependence on the attribute Unchecked_Access.
Avoid dependence on Ada.Unchecked_Conversion.
Avoid the direct invocation of or implicit dependence upon an underlying host operating system or Ada run-time support
system, except where the interface is explicitly defined in the
language (e.g., Annex C or D of the Ada Reference Manual [1995]).
Use standard bindings and the package Ada.Command_Line
when you need to invoke the underlying
run-time support system.
Use features defined in the Annexes rather than vendor-defined
features.
input/output
Use constants and variables as symbolic actuals for the Name
and Form parameters on the predefined I/O packages. Declare and initialize them in an implementation
dependency package.
Close all files explicitly.
Avoid performing I/O on access types.
Consider using Sequential_IO or Direct_IO
instead of Stream_IO unless you need the low-level, heterogeneous
I/O features provided by Stream_IO.
Consider using Current_Error and Set_Error
for run-time error messages.