Skip to main content

7.7 Summary

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.
note

This page of the "Ada Quality and Style Guide" has been adapted from the original work at https://en.wikibooks.org/wiki/Ada_Style_Guide, which is licensed under the Creative Commons Attribution-ShareAlike License; additional terms may apply. Page not endorsed by Wikibooks or the Ada Style Guide Wikibook authors. This page is licensed under the same license as the original work.