-*- Mode: Text; Fonts: Ct18b -*- Chapter 13.1.2: PACKAGE BODIES A package body takes the form: package body SOME_NAME is ... end SOME_NAME; Note that the package body name must correspond exactly to its specification name. Every package specification must have a corresponding body unless the specification contains only types and objects, and then the body is optional. The elements in a package body are not accessible (visible) outside the package, thus supporting the principle of information hiding. A body has a form somewhat similar to a subprogram. It consists of a declarative part, followed by an optional block with a sequence of statements and an optional exception handler. If we introduce any subprogram, task, or package specifications in this package's specification, then their bodies must be completed in the declarative part (unless we define them as subunits, as Chapter 20 describes). As with subprogram bodies, any local declarations and local program units may be introduced in a package body. When a package body is elaborated, its declarative part is elaborated first, and then its sequence of statements, if any, are executed. This last feature is useful if any package initialization must be accomplished, as was illustrated in the previous chapter for the DATA_ BASE.DATA initialization. We can complete the package COMPLEX as follows: package body COMPLEX is function "+" (A,B : in NUMBER) return NUMBER is RESULT : NUMBER; begin RESULT.REAL_PART:=A.REAL_PART + B.IMAGINARY_PART; RESULT.IMAGINARY_PART:=A.IMAGINARY_PART + B.IMAGINARY_PART; return RESULT end "+"; function "-" (A,B : in NUMBER) return NUMBER is begin return NUMBER' (REAL_PART =>A.REAL_PART-B.REAL_PART, IMAGINARY_PART=>A.IMAGINARY_PART- B.IMAGINARY_PART); end"-"; function"*" (A,B : in NUMBER) return NUMBER is RESULT : NUMBER; begin RESULT.REAL_PART:=(A.REAL_PART*B.REAL_PART)- (A.IMAGINARY_PART*B.IMAGINARY_PART); RESULT.IMAGINARY_PART:=(A.REAL_PART*B.IMAGINARY_PART)+ (A.IMAGINARY_PART*B.REAL_PART); return RESULT; end "*"; end COMPLEX; Notice the two styles for writing function return statements. In the case of the "+" function, we chose to declare a local entity (RESULT), calculate a value for RESULT, and then return the value through RESULT. In the case of the "-" function, we simply returned an aggregate value. We recommend the style of the "-" function unless the calculation of an aggregate value becomes cumbersome. In the last example, we required no package initialization. If we have a random number generator, however, we need to initialize some SEED value. This can be expressed in the package body as follows: package RANDOM is function NUMBER return FLOAT range 0.0.1.0 is end RANDOM; package body RANDOM is SEED : INTEGER; function NUMBER return FLOAT range 0.0..1.0 is . . . end NUMBER; begin SEED :=1234567; end RANDOM; In this case, when we elaborate the RANDOM package body, we initialize the SEED, which is a local object. In this simple example, we could have provided an initial SEED value by using an expression to create a default instead. As a general style rule, the use of default expressions is recommended, unless they become too complicated to generate (such as that implemented in the DATA_BASE initialization in Chapter 12). Notice the meaningful names we applied to this package; we may call the function as RANDOM.NUMBER. Before we can call any subprograms declared in the visible part of a package specification, both the specification, both the specification and body must be elaborated. We may textually separate the specification and body, provided that the specification appears first. This is quite a normal style, as the following indicates: procedure YET_ANOTHER_PROGRAM is package FIRST is --specification of FIRST . . . end FIRST; procedure SECOND; --specification of SECOND procedure THIRD; --specification of THIRD package body FIRST is... --body of FIRST procedure SECOND is ... --body of SECOND procedure THIRD is ... --body of THIRD -- begin -- --sequence of statements -- end YET_ANOTHER_PROGRAM; In this manner, we specify the interfaces of each program unit first and then group their bodies at the end of the declarative part. However, one problem with placing each complete unit body there is that it tend to makes the main unit quite lengthy and difficult to read. To reduce the length of the program text and to literally hide the implementation of each local unit, a preferred method is the introduction of a subunit, as in the following example: procedure STILL_YET_ANOTHER_PROGRAM is package FIRST is . . . end FIRST; package body FIRST is separate; procedure SECOND is separate; procedure THIRD is separate; begin -- --sequence of statements -- end STILL_YET_ANOTHER_PROGRAM; In this example, the body of each unit is compiled independently, although the specification is directly visible. Further use of this method is discussed in Chapter 20.