Ada 95 Quality and Style Guide Chapter 7
Discussions concerning portability usually concentrate on the differences in computer systems, but the
development and run-time environment may also change:
Most portability problems are not pure language issues. Portability involves hardware (byte order, device I/O) and
software (utility libraries, operating systems, run-time libraries). This chapter will not address these challenging
This chapter does identify the more common portability problems that are specific to Ada when moving from one
platform or compiler to another. It also suggests ways that nonportable code can be isolated. By using the
implementation hiding features of Ada, the cost of porting can be significantly reduced.
In fact, many language portability issues are solved by the strict definition of the Ada language itself. In most
programming languages, different dialects are prevalent as vendors extend or dilute a language for various
reasons: conformance to a programming environment or features for a particular application domain. The Ada
Compiler Validation Capability (ACVC) was developed by the U.S. Department of Defense at the Ada Validation
Facility, ASD/SIDL, Wright-Patterson Air Force Base, to ensure that implementors strictly adhered to the Ada
As part of the strict definition of Ada, certain constructs are defined to be erroneous, and the effect of executing
an erroneous construct is unpredictable. Therefore, erroneous constructs are obviously not portable. Erroneous
constructs and bounded errors are discussed in Guideline 5.9.1 through 5.9.10 and are not repeated in this chapter.
Most programmers new to the language expect Ada to eliminate all portability problems; it definitely does not.
Certain areas of Ada are not yet covered by validation. The definition of Ada leaves certain details to the
implementor. The compiler implementor's choices, with respect to these details, affect portability.
The revisions to the Ada language approved in the 1995 standard generate a new area of portability concerns.
Some programs are intended to have a long life and may start in Ada 83 (Ada Reference Manual 1983) but
transition to Ada 95 (Ada Reference Manual 1995). Although this style guide focuses on the current Ada standard
and does not address transition issues, there are portability issues relating to using certain features of the language.
These issues revolve around the language features designated as obsolescent in Annex J of the Ada Reference
The constructs of the language have been developed to satisfy a series of needs. These constructs can legitimately
be used even though they may impact portability. There are some general principles to enhancing portability that
are exemplified by many of the guidelines in this chapter. They are:
- Recognize those Ada constructs that may adversely affect portability on the relevant implementations or
- Rely on those Ada constructs that depend on characteristics shared by all relevant implementations.
Avoid the use of those constructs whose implementation characteristics vary on the relevant platforms.
- Localize and encapsulate nonportable features of a program if their use is essential.
- Highlight the use of constructs that may cause portability problems.
These guidelines cannot be applied thoughtlessly. Many of them involve a detailed understanding of the Ada
model and its implementation. In many cases, you will have to make carefully considered tradeoffs between
efficiency and portability. Reading this chapter should improve your insight into the tradeoffs involved.
The material in this chapter was largely acquired from three sources: the Ada Run-Time Environments Working
Group (ARTEWG) Catalogue of Ada Runtime Implementation Dependencies (ARTEWG 1986); the Nissen and
Wallis book on Portability and Style in Ada (Nissen and Wallis 1984); and a paper written for the U.S. Air Force
by SofTech on Ada Portability Guidelines (Pappas 1985). The last of these sources (Pappas 1985) encompasses
the other two and provides an in-depth explanation of the issues, numerous examples, and techniques for
minimizing portability problems. Conti (1987) is a valuable reference for understanding the latitude allowed for
implementors of Ada and the criteria often used to make decisions.
This chapter's purpose is to provide a summary of portability issues in the guideline format of this book. The
chapter does not include all issues identified in the references but only the most significant. For an in-depth
presentation, see Pappas (1985). A few additional guidelines are presented here and others are elaborated upon
where applicable. For further reading on Ada I/O portability issues, see Matthews (1987), Griest (1989), and
Some of the guidelines in this chapter cross reference and place stricter constraints on other guidelines in this
book. These constraints apply when portability is being emphasized.
Guidelines in this chapter are frequently worded "consider . . ." because hard and fast rules cannot apply in all
situations. The specific choice you make in a given situation involves design tradeoffs. The rationale for these
guidelines is intended to give you insight into some of these tradeoffs.
This section introduces some generally applicable principles of writing portable Ada programs. It includes
guidelines about the assumptions you should make with respect to a number of Ada features and their
implementations and guidelines about the use of other Ada features to ensure maximum portability.
7.1.1 Obsolescent Features
- 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
- 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
7.1.2 Global Assumptions
- 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.
- 16 bits available for type Integer (-2**15 .. 2**15 - 1)
- 6 decimal digits of precision available for floating-point types
- 24 bits available for fixed-point types
- 200 characters per line of source text
- 16 bits for expressions
- -86_400 .. 86_400 seconds (1 day) for the range of Duration (as specified in Ada Reference
Manual [1995, §9.6])
- 20 milliseconds for Duration'Small (as specified in Ada Reference Manual [1995, §9.6])
- Use highlighting comments for each package, subprogram, and task where any nonportable features are
- For each nonportable feature employed, describe the expectations for that feature.
Explicitly commenting each breach of portability will raise its visibility and aid in the porting process. A
description of the nonportable feature's expectations covers the common case where vendor documentation of
the original implementation is not available to the person performing the porting process.
7.1.4 Main Subprogram
- 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 (see Guideline 7.1.6).
- Encapsulate and document all uses of package Ada.Command_Line.
7.1.5 Encapsulating Implementation Dependencies
- 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
- For the packages that hide implementation dependencies, maintain different package bodies for different
- 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.
7.1.6 Implementation-Added 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.
7.1.7 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).
7.1.8 Dependence on Parameter Passing Mechanism
- 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.
7.1.9 Arbitrary Order Dependencies
- Avoid depending on the order in which certain constructs in Ada are evaluated.
7.2 NUMERIC TYPES AND EXPRESSIONS
A great deal of care was taken with the design of the Ada features related to numeric computations to ensure that
the language could be used in embedded systems and mathematical applications where precision was important.
As far as possible, these features were made portable. However, there is an inevitable tradeoff between maximally
exploiting the available precision of numeric computation on a particular machine and maximizing the portability
of Ada numeric constructs. This means that these Ada features, particularly numeric types and expressions, must
be used with great care if full portability of the resulting program is to be guaranteed.
7.2.1 Predefined Numeric Types
- 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
- 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
7.2.2 Accuracy Model
- Use an implementation that supports the Numerics Annex (Ada Reference Manual 1995, Annex G) when
performance and accuracy are overriding concerns.
7.2.3 Accuracy Analysis
- Carefully analyze what accuracy and precision you really need.
7.2.4 Accuracy Constraints
- Do not press the accuracy limits of the machine(s).
- Comment the analysis and derivation of the numerical aspects of a program.
7.2.6 Subexpression Evaluation
- 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 (see Guidelines
3.4.1, 5.3.1, and 5.5.3).
7.2.7 Relational Tests
- Consider using <= and >= to do relational tests on real valued arguments, avoiding the <, >, =, and /=
- Use values of type attributes in comparisons and checking for small values.
7.2.8 Decimal Types and the Information Systems Annex
- 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
- Declare subtypes of the appropriately scaled decimal type to provide appropriate range constraints for
- 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.
7.3 STORAGE CONTROL
The management of dynamic storage can vary between Ada environments. In fact, some environments do not
provide any deallocation. The following Ada storage control mechanisms are implementation-dependent and
should be used with care in writing portable programs.
7.3.1 Representation Clause
- Do not use a representation clause to specify number of storage units.
7.3.2 Access-to-Subprogram Values
- Do not compare access-to-subprogram values.
7.3.3 Storage Pool Mechanisms
- Consider using explicitly defined storage pool mechanisms.
The definition of tasking in the Ada language leaves many characteristics
of the tasking model up to the implementor. This allows a vendor
to make appropriate tradeoffs for the intended application domain,
but it also diminishes the portability of designs and code employing
the tasking features. In some respects, this diminished portability
is an inherent characteristic of concurrency approaches (see Nissen
and Wallis 1984, 37).
A discussion of Ada tasking dependencies when employed in a distributed
target environment is beyond the scope of this book. For example,
multiprocessor task scheduling, interprocessor rendezvous, and
the distributed sense of time through package Calendar
are all subject to differences between implementations. For more
information, Nissen and Wallis (1984) and ARTEWG (1986) touch
on these issues, and Volz et al. (1985) is one of many research
If the Real-Time Systems Annex is supported, then many concurrency
aspects are fully defined and, therefore, a program can rely on
these features while still being portable to other implementations
that conform to the
Real-Time Systems Annex. The following sections provide
guidelines based on the absence of this annex.
7.4.1 Task Activation Order
- Do not depend on the order in which task objects are activated
when declared in the same declarative list.
7.4.2 Delay Statements
7.4.3 Package Calendar, Type Duration, and System.Tick
- 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.
7.4.4 Select Statement Evaluation Order
- Do not assume a correlation between System.Tick and
type Duration (see Guidelines 6.1.7 and 7.4.2).
Chapter 7 Continued
- Do not depend on the order in which guard
conditions are evaluated or on the algorithm for choosing among
several open select alternatives.