In this section... 4.1.1 Separate Compilation Capabilities 4.1.2 Subprograms 4.1.3 Functions 4.1.4 Packages 4.1.5 Cohesion 4.1.6 Data Coupling 4.1.7 Tasks
|
| Summary of Guidelines from this section |
text_io_.ada -- the specification text_io.ada -- the body text_io__integer_io.ada -- a subunit text_io__fixed_io.ada -- a subunit text_io__float_io.ada -- a subunit text_io__enumeration_io.ada -- a subunit |
For the same reason, use subunits for large nested bodies, and put each subunit in its own file. This makes it possible to modify the body of the one nested unit without having to recompile any of the other units in the body. This is recommended for large units because changes are more likely to occur in large units than in small ones.
An additional benefit of using multiple separate files is that it allows different implementers to modify different parts of the system at the same time with conventional editors which do not allow multiple concurrent updates to a single file.
Finally, keeping bodies and specifications separate makes it possible to have multiple bodies for the same specification, or multiple specifications for the same body. Although Ada requires that there be exactly one specification per body in a system at any given time, it can still be useful to maintain multiple bodies or multiple specifications for use in different builds of a system. For example, a single specification may have multiple bodies, each of which implements the same functionality with a different tradeoff of time versus space efficiency. Or, for machine-dependent code, there may be one body for each target machine. Maintaining multiple package specifications can also be useful during development and test. You may develop one specification for delivery to your customer and another for unit testing. The first one would export only those subprograms intended to be called from outside of the package during normal operation of the system. The second one would export all subprograms of the package so that each of them could be independently tested.
A consistent file naming convention is recommended to make it easier to manage the large number of files which may result from following this guideline.
Language Ref Manual references: 6.1 Subprogram Declarations, 7.2 Package Specifications and Declarations, 7.3 Package Bodies, 10.1 Compilation Units - Library Units, 10.2 Subunits of Compilation Units, 10 Program Structure and Compilation Issues, F Implementation-Dependent Characteristics
...
----------------------------------------------------------------------
procedure Dispatch_To_Device
(Output : in Text;
Device : in Device_Name;
Status : out Error_Codes) is
Upper_Case_Output : Text (1 .. Output'Length);
...
begin -- Dispatch_To_Device
...
case Device.Character_Set is
when Limited_ASCII =>
Convert_To_Upper_Case(Original => Output,
Upper_Case => Upper_Case_Output);
...
when Extended_ASCII =>
...
when EBCDIC =>
...
end case; -- Device_Type.Character_Set
...
end Dispatch_To_Device;
---------------------------------------------------------------------- |
Language Ref Manual references: 6 Subprograms
function Next_Character return Character is separate; |
However, the use of a function like this should could lead to a subtle
problem. Any time the order of evaluation is undefined, the order of the
values returned by the function will effectively be undefined. In this
example, the order of the characters placed in Word and the order that the
following two characters are given to the Suffix parameters is unknown. No
implementation of the Next_Character function can guarantee which character
will go where:
Word : constant String := String'(1 .. 5 => Next_Character);
begin -- Start_Parsing
Parse(Keyword => Word,
Suffix1 => Next_Character,
Suffix2 => Next_Character);
end Start_Parsing; |
Of course, if the order is unimportant (as in a random number generator), then the order of evaluation is unimportant.
Language Ref Manual references: 6.4 Subprogram Calls, 6.5 Function Subprograms, 8.3 Visibility
Backing_Storage_Interface could contain type and subprogram
declarations to support a generalized view of an external memory system (such
as a disk or drum). Its internals may, in turn, depend on other packages more
specific to the hardware or operating system.
Encapsulating areas of potential change helps to minimize the effort required to implement that change by preventing unnecessary dependencies among unrelated parts of the system.
Language Ref Manual references: 3 Declarations and Types, 6.1 Subprogram Declarations, 7 Packages, 8.3 Visibility, 13 Representation Clauses and Implementation-Dependent Features, B Predefined Language Pragmas
Project_Definitions is obviously a "catch
all" for a particular project and is likely to be a jumbled mess. It probably
has this form to permit project members to incorporate a single with clause
into their software.
Better examples are packages called Display_Format_Definitions, containing all
the types and constants needed by some specific display in a specific format,
and Cartridge_Tape_Handler, containing all the types, constants, and
subprograms which provide an interface to a special purpose device.
The degree to which the entities in a package are related has a direct impact on the ease of understanding packages and programs made up of packages. There are different criteria for grouping, and some criteria are less effective than others. Grouping the class of data or activity (e.g., initialization modules) or grouping data or activities based on their timing characteristics is less effective than grouping based on function or need to communicate through data (Charette 1986 paraphrased).
Language Ref Manual references: 3.2 Objects and Named Numbers, 3.3 Types and Subtypes, 6.1 Subprogram Declarations, 7 Packages
------------------------------------------------------------------------- package Compilation_Status is type Line_Range is range 1 .. 2_500_000; function Source_Line_Number return Line_Range; end Compilation_Status; ------------------------------------------------------------------------- with Compilation_Status; package Error_Message_Processing is -- Handle compile-time diagnostic. end Error_Message_Processing; ------------------------------------------------------------------------- with Compilation_Status; package Code_Generation is -- Operations for code generation. end Code_Generation; ------------------------------------------------------------------------- |
Language Ref Manual references: 3.2.1 Object Declarations, 7.2 Package Specifications and Declarations, 8.2 Scope of Declarations
Language Ref Manual references: 9 Tasks, 13.5.1 Interrupts