The Ada Joint Program Office does not guarantee the accuracy of this file, as compared with the contents of ANSI/MIL-STD-1815A-1983, the Reference Manual for the Ada Programming Language. If errors or discrepancies are found in this machine-readable version, please forward comments via the Defense Data Network (DDN) to: ACTION@AJPO.SEI.CMU.EDU or via conventional mail to Ada Information Clearinghouse 3D139 (1211 S. Fern, C-107) The Pentagon Washington, D.C. 20301-3081 ----------------------------------------------------------------------- Copyright 1980, 1982, 1983 owned by the United States Government as represented by the Under Secretary of Defense, Research and Engineering. All rights reserved. Provided that notice of copyright is included on the first page, this document may be copied in its entirety without alteration or as altered by (1) adding text that is clearly marked as an insertion; (2) shading or highlighting existing text; (3) deleting examples. Permission to publish other excerpts should be obtained from the Ada Joint Program Office, OUSDRE (R&AT), The Pentagon, Washington, DC 20301-2081, U.S.A. 7. Packages Packages are one of the four forms of program unit, of which programs can be composed. The other forms are subprograms, task units, and generic units. Packages allow the specification of groups of logically related entities. In their simplest form packages specify pools of common object and type declarations. More generally, packages can be used to specify groups of related entities including also subprograms that can be called from outside the package, while their inner workings remain concealed and protected from outside users. References: generic unit 12, program unit 6, subprogram 6, task unit 9, type declaration 3.3.1 7.1 Package Structure A package is generally provided in two parts: a package specification and a package body. Every package has a package specification, but not all packages have a package body. package_declaration ::= package_specification; package_specification ::= package identifier is {basic_declarative_item} [private {basic_declarative_item}] end [package_simple_name] package_body ::= package body package_simple_name is [declarative_part] [begin sequence_of_statements [exception exception_handler {exception_handler}]] end [package_simple_name]; The simple name at the start of a package body must repeat the package identifier. Similarly if a simple name appears at the end of the package specification or body, it must repeat the package identifier. If a subprogram declaration, a package declaration, a task declaration, or a generic declaration is a declarative item of a given package specification, then the body (if there is one) of the program unit declared by the declarative item must itself be a declarative item of the declarative part of the body of the given package. Notes: A simple form of package, specifying a pool of objects and types, does not require a package body. One of the possible uses of the sequence of statements of a package body is to initialize such objects. For each subprogram declaration there must be a corresponding body (except for a subprogram written in another language, as explained in section 13.9). If the body of a program unit is a body stub, then a separately compiled subunit containing the corresponding proper body is required for the program unit (see 10.2). A body is not a basic declarative item and so cannot appear in a package specification. A package declaration is either a library package (see 10.2) or a declarative item declared within another program unit. References: basic declarative item 3.9, body stub 10.2, declarative item 3.9, declarative part 3.9, exception handler 11.2, generic body 12.2, generic declaration 12.1, identifier 2.3, library unit 10.1, object 3.2, package body 7.3, program unit 6, proper body 3.9, sequence of statements 5.1, simple name 4.1, subprogram body 6.3, subprogram declaration 6.1, subunit 10.2, task body 9.1, task declaration 9.1, type 3.3 7.2 Package Specifications and Declarations The first list of declarative items of a package specification is called the visible part of the package. The optional list of declarative items after the reserved word private is called the private part of the package. An entity declared in the private part of a package is not visible outside the package itself (a name denoting such an entity is only possible within the package). In contrast, expanded names denoting entities declared in the visible part can be used even outside the package; furthermore, direct visibility of such entities can be achieved by means of use clauses (see 4.1.3 and 8.4). The elaboration of a package declaration consists of the elaboration of its basic declarative items in the given order. Notes: The visible part of a package contains all the information that another program unit is able to know about the package. A package consisting of only a package specification (that is, without a package body) can be used to represent a group of common constants or variables, or a common pool of objects and types, as in the examples below. Example of a package describing a group of common variables: package PLOTTING_DATA is PEN_UP : BOOLEAN; CONVERSION_FACTOR, X_OFFSET, Y_OFFSET, X_MIN, Y_MIN, X_MAX, Y_MAX: REAL; -- see 3.5.7 X_VALUE : array (1 .. 500) of REAL; Y_VALUE : array (1 .. 500) of REAL; end PLOTTING_DATA; Example of a package describing a common pool of objects and types: package WORK_DATA is type DAY is (MON, TUE, WED, THU, FRI, SAT, SUN); type HOURS_SPENT is delta 0.25 range 0.0 .. 24.0; type TIME_TABLE is array (DAY) of HOURS_SPENT; WORK_HOURS : TIME_TABLE; NORMAL_HOURS : constant TIME_TABLE := (MON .. THU => 8.25, FRI => 7.0, SAT | SUN => 0.0); end WORK_DATA; References: basic declarative item 3.9, constant 3.2.1, declarative item 3.9, direct visibility 8.3, elaboration 3.9, expanded name 4.1.3, name 4.1, number declaration 3.2.2, object declaration 3.2.1, package 7, package declaration 7.1, package identifier 7.1, package specification 7.1, scope 8.2, simple name 4.1, type declaration 3.3.1, use clause 8.4, variable 3.2.1 7.3 Package Bodies In contrast to the entities declared in the visible part of a package specification, the entities declared in the package body are only visible within the package body itself. As a consequence, a package with a package body can be used for the construction of a group of related subprograms (a package in the usual sense), in which the logical operations available to the users are clearly isolated from the internal entities. For the elaboration of a package body, its declarative part is first elaborated, and its sequence of statements (if any) is then executed. The optional exception handlers at the end of a package body service exceptions raised during the execution of the sequence of statements of the package body. Notes: A variable declared in the body of a package is only visible within this body and, consequently, its value can only be changed within the package body. In the absence of local tasks, the value of such a variable remains unchanged between calls issued from outside the package to subprograms declared in the visible part. The properties of such a variable are similar to those of an "own" variable of Algol 60. The elaboration of the body of a subprogram declared in the visible part of a package is caused by the elaboration of the body of the package. Hence a call of such a subprogram by an outside program unit raises the exception PROGRAM_ERROR if the call takes place before the elaboration of the package body (see 3.9). Example of a package: package RATIONAL_NUMBERS is type RATIONAL is record NUMERATOR : INTEGER; DENOMINATOR : POSITIVE; end record; function EQUAL(X,Y : RATIONAL) return BOOLEAN; function "/" (X,Y : INTEGER) return RATIONAL; -- to construct a rational number function "+" (X,Y : RATIONAL) return RATIONAL; function "-" (X,Y : RATIONAL) return RATIONAL; function "*" (X,Y : RATIONAL) return RATIONAL; function "/" (X,Y : RATIONAL) return RATIONAL; end; package body RATIONAL_NUMBERS is procedure SAME_DENOMINATOR (X,Y : in out RATIONAL) is begin -- reduces X and Y to the same denominator: ... end; function EQUAL(X,Y : RATIONAL) return BOOLEAN is U,V : RATIONAL; begin U := X; V := Y; SAME_DENOMINATOR (U,V); return U.NUMERATOR = V.NUMERATOR; end EQUAL; function "/" (X,Y : INTEGER) return RATIONAL is begin if Y > 0 then return (NUMERATOR => X, DENOMINATOR => Y); else return (NUMERATOR => -X, DENOMINATOR => -Y); end if; end "/"; function "+" (X,Y : RATIONAL) return RATIONAL is ... end "+"; function "-" (X,Y : RATIONAL) return RATIONAL is ... end "-"; function "*" (X,Y : RATIONAL) return RATIONAL is ... end "*"; function "/" (X,Y : RATIONAL) return RATIONAL is ... end "/"; end RATIONAL_NUMBERS; References: declaration 3.1, declarative part 3.9, elaboration 3.1 3.9, exception 11, exception handler 11.2, name 4.1, package specification 7.1, program unit 6, program_error exception 11.1, sequence of statements 5.1, subprogram 6, variable 3.2.1, visible part 7.2 7.4 Private Type and Deferred Constant Declarations The declaration of a type as a private type in the visible part of a package serves to separate the characteristics that can be used directly by outside program units (that is, the logical properties) from other characteristics whose direct use is confined to the package (the details of the definition of the type itself). Deferred constant declarations declare constants of private types. private_type_declaration ::= type identifier [discriminant_part] is [limited] private; deferred_constant_declaration ::= identifier_list : constant type_mark; A private type declaration is only allowed as a declarative item of the visible part of a package, or as the generic parameter declaration for a generic formal type in a generic formal part. The type mark of a deferred constant declaration must denote a private type or a subtype of a private type; a deferred constant declaration and the declaration of the corresponding private type must both be declarative items of the visible part of the same package. A deferred constant declaration with several identifiers is equivalent to a sequence of single deferred constant declarations as explained in section 3.2. Examples of private type declarations: type KEY is private; type FILE_NAME is limited private; Example of deferred constant declaration: NULL_KEY : constant KEY; References: constant 3.2.1, declaration 3.1, declarative item 3.9, deferred constant 7.4.3, discriminant part 3.7.1, generic formal part 12.1, generic formal type 12.1, generic parameter declaration 12.1, identifier 2.3, identifier list 3.2, limited type 7.4.4, package 7, private type 7.4.1, program unit 6, subtype 3.3, type 3.3, type mark 3.3.2, visible part 7.2 7.4.1 Private Types If a private type declaration is given in the visible part of a package, then a corresponding declaration of a type with the same identifier must appear as a declarative item of the private part of the package. The corresponding declaration must be either a full type declaration or the declaration of a task type. In the rest of this section explanations are given in terms of full type declarations; the same rules apply also to declarations of task types. A private type declaration and the corresponding full type declaration define a single type. The private type declaration, together with the visible part, define the operations that are available to outside program units (see section 7.4.2 on the operations that are available for private types). On the other hand, the full type declaration defines other operations whose direct use is only possible within the package itself. If the private type declaration includes a discriminant part, the full declaration must include a discriminant part that conforms (see 6.3.1 for the conformance rules) and its type definition must be a record type definition. Conversely, if the private type declaration does not include a discriminant part, the type declared by the full type declaration (the full type) must not be an unconstrained type with discriminants. The full type must not be an unconstrained array type. A limited type (in particular a task type) is allowed for the full type only if the reserved word limited appears in the private type declaration (see 7.4.4). Within the specification of the package that declares a private type and before the end of the corresponding full type declaration, a restriction applies to the use of a name that denotes the private type or a subtype of the private type and, likewise, to the use of a name that denotes any type or subtype that has a subcomponent of the private type. The only allowed occurrences of such a name are in a deferred constant declaration, a type or subtype declaration, a subprogram specification, or an entry declaration; moreover, occurrences within derived type definitions or within simple expressions are not allowed. The elaboration of a private type declaration creates a private type. If the private type declaration has a discriminant part, this elaboration includes that of the discriminant part. The elaboration of the full type declaration consists of the elaboration of the type definition; the discriminant part, if any, is not elaborated (since the conforming discriminant part of the private type declaration has already been elaborated). Notes: It follows from the given rules that neither the declaration of a variable of a private type, nor the creation by an allocator of an object of the private type are allowed before the full declaration of the type. Similarly before the full declaration, the name of the private type cannot be used in a generic instantiation or in a representation clause. References: allocator 4.8, array type 3.6, conform 6.3.1, declarative item 3.9, deferred constant declaration 7.4.3, derived type 3.4, discriminant part 3.7.1, elaboration 3.9, entry declaration 9.5, expression 4.4, full type declaration 3.3.1, generic instantiation 12.3, identifier 2.3, incomplete type declaration 3.8.1, limited type 7.4.4, name 4.1, operation 3.3, package 7, package specification 7.1, private part 7.2, private type 7.4, private type declaration 7.4, record type definition 3.7, representation clause 13.1, reserved word 2.9, subcomponent 3.3, subprogram specification 6.1, subtype 3.3, subtype declaration 3.3.2, type 3.3, type declaration 3.3.1, type definition 3.3.1, unconstrained array type 3.6, variable 3.2.1, visible part 7.2 7.4.2 Operations of a Private Type The operations that are implicitly declared by a private type declaration include basic operations. These are the operations involved in assignment (unless the reserved word limited appears in the declaration), membership tests, selected components for the selection of any discriminant, qualification, and explicit conversions. For a private type T, the basic operations also include the attributes T'BASE (see 3.3.3) and T'SIZE (see 13.7.2). For an object A of a private type, the basic operations include the attribute A'CONSTRAINED if the private type has discriminants (see 3.7.4), and in any case, the attributes A'SIZE and A'ADDRESS (see 13.7.2). Finally, the operations implicitly declared by a private type declaration include the predefined comparison for equality and inequality unless the reserved word limited appears in the private type declaration. The above operations, together with subprograms that have a parameter or result of the private type and that are declared in the visible part of the package, are the only operations from the package that are available outside the package for the private type. Within the package that declares the private type, the additional operations implicitly declared by the full type declaration are also available. However, the redefinition of these implicitly declared operations is allowed within the same declarative region, including between the private type declaration and the corresponding full declaration. An explicitly declared subprogram hides an implicitly declared operation that has the same parameter and result type profile (this is only possible if the implicitly declared operation is a derived subprogram or a predefined operator). If a composite type has subcomponents of a private type and is declared outside the package that declares the private type, then the operations that are implicitly declared by the declaration of the composite type include all operations that only depend on the characteristics that result from the private type declaration alone. (For example the operator < is not included for a one-dimensional array type.) If the composite type is itself declared within the package that declares the private type (including within an inner package or generic package), then additional operations that depend on the characteristics of the full type are implicitly declared, as required by the rules applicable to the composite type (for example the operator < is declared for a one-dimensional array type if the full type is discrete). These additional operations are implicitly declared at the earliest place within the immediate scope of the composite type and after the full type declaration. The same rules apply to the operations that are implicitly declared for an access type whose designated type is a private type or a type declared by an incomplete type declaration. For every private type or subtype T the following attribute is defined: T'CONSTRAINED Yields the value FALSE if T denotes an unconstrained nonformal private type with discriminants; also yields the value FALSE if T denotes a generic formal private type, and the associated actual subtype is either an unconstrained type with discriminants or an unconstrained array type; yields the value TRUE otherwise. The value of this attribute is of the predefined type BOOLEAN. Note: A private type declaration and the corresponding full type declaration define two different views of one and the same type. Outside of the defining package the characteristics of the type are those defined by the visible part. Within these outside program units the type is just a private type and any language rule that applies only to another class of types does not apply. The fact that the full declaration might implement the private type with a type of a particular class (for example, as an array type) is only relevant within the package itself. The consequences of this actual implementation are, however, valid everywhere. For example: any default initialization of components takes place; the attribute SIZE provides the size of the full type; task dependence rules still apply to components that are task objects. Example: package KEY_MANAGER is type KEY is private; NULL_KEY : constant KEY; procedure GET_KEY(K : out KEY); function "<" (X, Y : KEY) return BOOLEAN; private type KEY is new NATURAL; NULL_KEY : constant KEY := 0; end; package body KEY_MANAGER is LAST_KEY : KEY := 0; procedure GET_KEY(K : out KEY) is begin LAST_KEY := LAST_KEY + 1; K := LAST_KEY; end GET_KEY; function "<" (X, Y : KEY) return BOOLEAN is begin return INTEGER(X) < INTEGER(Y); end "<"; end KEY_MANAGER; Notes on the example: Outside of the package KEY_MANAGER, the operations available for objects of type KEY include assignment, the comparison for equality or inequality, the procedure GET_KEY and the operator "<"; they do not include other relational operators such as ">=", or arithmetic operators. The explicitly declared operator "<" hides the predefined operator "<" implicitly declared by the full type declaration. Within the body of the function, an explicit conversion of X and Y to the type INTEGER is necessary to invoke the "<" operator of this type. Alternatively, the result of the function could be written as not (X >= Y), since the operator ">=" is not redefined. The value of the variable LAST_KEY, declared in the package body, remains unchanged between calls of the procedure GET_KEY. (See also the Notes of section 7.3.) References: assignment 5.2, attribute 4.1.4, basic operation 3.3.3, component 3.3, composite type 3.3, conversion 4.6, declaration 3.1, declarative region 8.1, derived subprogram 3.4, derived type 3.4, dimension 3.6, discriminant 3.3, equality 4.5.2, full type 7.4.1, full type declaration 3.3.1, hiding 8.3, immediate scope 8.2, implicit declaration 3.1, incomplete type declaration 3.8.1, membership test 4.5, operation 3.3, package 7, parameter of a subprogram 6.2, predefined function 8.6, predefined operator 4.5, private type 7.4, private type declaration 7.4, program unit 6, qualification 4.7, relational operator 4.5, selected component 4.1.3, subprogram 6, task dependence 9.4, visible part 7.2 7.4.3 Deferred Constants If a deferred constant declaration is given in the visible part of a package then a constant declaration (that is, an object declaration declaring a constant object, with an explicit initialization) with the same identifier must appear as a declarative item of the private part of the package. This object declaration is called the full declaration of the deferred constant. The type mark given in the full declaration must conform to that given in the deferred constant declaration (see 6.3.1). Multiple or single declarations are allowed for the deferred and the full declarations, provided that the equivalent single declarations conform. Within the specification of the package that declares a deferred constant and before the end of the corresponding full declaration, the use of a name that denotes the deferred constant is only allowed in the default expression for a record component or for a formal parameter (not for a generic formal parameter). The elaboration of a deferred constant declaration has no other effect. The execution of a program is erroneous if it attempts to use the value of a deferred constant before the elaboration of the corresponding full declaration. Note: The full declaration for a deferred constant that has a given private type must not appear before the corresponding full type declaration. This is a consequence of the rules defining the allowed uses of a name that denotes a private type (see 7.4.1). References: conform 6.3.1, constant declaration 3.2.1, declarative item 3.9, default expression for a discriminant 3.7.1, deferred constant 7.4, deferred constant declaration 7.4, elaboration has no other effect 3.1, formal parameter 6.1, generic formal parameter 12.1 12.3, identifier 2.3, object declaration 3.2.1, package 7, package specification 7.1, private part 7.2, record component 3.7, type mark 3.3.2, visible part 7.2 7.4.4 Limited Types A limited type is a type for which neither assignment nor the predefined comparison for equality and inequality is implicitly declared. A private type declaration that includes the reserved word limited declares a limited type. A task type is a limited type. A type derived from a limited type is itself a limited type. Finally, a composite type is limited if the type of any of its subcomponents is limited. The operations available for a private type that is limited are as given in section 7.4.2 for private types except for the absence of assignment and of a predefined comparison for equality and inequality. For a formal parameter whose type is limited and whose declaration occurs in an explicit subprogram declaration, the mode out is only allowed if this type is private and the subprogram declaration occurs within the visible part of the package that declares the private type. The same holds for formal parameters of entry declarations and of generic procedure declarations. The corresponding full type must not be limited if the mode out is used for any such formal parameter. Otherwise, the corresponding full type is allowed (but not required) to be a limited type (in particular, it is allowed to be a task type). If the full type corresponding to a limited private type is not itself limited, then assignment for the type is available within the package, but not outside. The following are consequences of the rules for limited types: - An explicit initialization is not allowed in an object declaration if the type of the object is limited. - A default expression is not allowed in a component declaration if the type of the record component is limited. - An explicit initial value is not allowed in an allocator if the designated type is limited. - A generic formal parameter of mode in must not be of a limited type. Notes: The above rules do not exclude a default expression for a formal parameter of a limited type; they do not exclude a deferred constant of a limited type if the full type is not limited. An explicit declaration of an equality operator is allowed for a limited type (see 6.7). Aggregates are not available for a limited composite type (see 3.6.2 and 3.7.4). Catenation is not available for a limited array type (see 3.6.2). Example: package I_O_PACKAGE is type FILE_NAME is limited private; procedure OPEN (F : in out FILE_NAME); procedure CLOSE(F : in out FILE_NAME); procedure READ (F : in FILE_NAME; ITEM : out INTEGER); procedure WRITE(F : in FILE_NAME; ITEM : in INTEGER); private type FILE_NAME is record INTERNAL_NAME : INTEGER := 0; end record; end I_O_PACKAGE; package body I_O_PACKAGE is LIMIT : constant := 200; type FILE_DESCRIPTOR is record ... end record; DIRECTORY : array (1 .. LIMIT) of FILE_DESCRIPTOR; ... procedure OPEN (F : in out FILE_NAME) is ... end; procedure CLOSE(F : in out FILE_NAME) is ... end; procedure READ (F : in FILE_NAME; ITEM : out INTEGER) is ... end; procedure WRITE(F : in FILE_NAME; ITEM : in INTEGER) is ... end; begin ... end I_O_PACKAGE; Notes on the example: In the example above, an outside subprogram making use of I_O_PACKAGE may obtain a file name by calling OPEN and later use it in calls to READ and WRITE. Thus, outside the package, a file name obtained from OPEN acts as a kind of password; its internal properties (such as containing a numeric value) are not known and no other operations (such as addition or comparison of internal names) can be performed on a file name. This example is characteristic of any case where complete control over the operations of a type is desired. Such packages serve a dual purpose. They prevent a user from making use of the internal structure of the type. They also implement the notion of an encapsulated data type where the only operations on the type are those given in the package specification. References: aggregate 4.3, allocator 4.8, assignment 5.2, catenation operator 4.5, component declaration 3.7, component type 3.3, composite type 3.3, default expression for a discriminant 3.7, deferred constant 7.4.3, derived type 3.4, designate 3.8, discriminant specification 3.7.1, equality 4.5.2, formal parameter 6.1, full type 7.4.1, full type declaration 3.3.1, generic formal parameter 12.1 12.3, implicit declaration 3.1, initial value 3.2.1, mode 12.1.1, object 3.2, operation 3.3, package 7, predefined operator 4.5, private type 7.4, private type declaration 7.4, record component 3.7, record type 3.7, relational operator 4.5, subcomponent 3.3, subprogram 6, task type 9.1 9.2, type 3.3 7.5 Example of a Table Management Package The following example illustrates the use of packages in providing high level procedures with a simple interface to the user. The problem is to define a table management package for inserting and retrieving items. The items are inserted into the table as they are supplied. Each inserted item has an order number. The items are retrieved according to their order number, where the item with the lowest order number is retrieved first. From the user's point of view, the package is quite simple. There is a type called ITEM designating table items, a procedure INSERT for inserting items, and a procedure RETRIEVE for obtaining the item with the lowest order number. There is a special item NULL_ITEM that is returned when the table is empty, and an exception TABLE_FULL which is raised by INSERT if the table is already full. A sketch of such a package is given below. Only the specification of the package is exposed to the user. package TABLE_MANAGER is type ITEM is record ORDER_NUM : INTEGER; ITEM_CODE : INTEGER; QUANTITY : INTEGER; ITEM_TYPE : CHARACTER; end record; NULL_ITEM : constant ITEM := (ORDER_NUM | ITEM_CODE | QUANTITY => 0, ITEM_TYPE => ' '); procedure INSERT (NEW_ITEM : in ITEM); procedure RETRIEVE(FIRST_ITEM : out ITEM); TABLE_FULL : exception; -- raised by INSERT when table full end; The details of implementing such packages can be quite complex; in this case they involve a two-way linked table of internal items. A local housekeeping procedure EXCHANGE is used to move an internal item between the busy and the free lists. The initial table linkages are established by the initialization part. The package body need not be shown to the users of the package. package body TABLE_MANAGER is SIZE : constant := 2000; subtype INDEX is INTEGER range 0 .. SIZE; type INTERNAL_ITEM is record CONTENT : ITEM; SUCC : INDEX; PRED : INDEX; end record; TABLE : array (INDEX) of INTERNAL_ITEM; FIRST_BUSY_ITEM : INDEX := 0; FIRST_FREE_ITEM : INDEX := 1; function FREE_LIST_EMPTY return BOOLEAN is ... end; function BUSY_LIST_EMPTY return BOOLEAN is ... end; procedure EXCHANGE (FROM : in INDEX; TO : in INDEX) is ... end; procedure INSERT (NEW_ITEM : in ITEM) is begin if FREE_LIST_EMPTY then raise TABLE_FULL; end if; -- remaining code for INSERT end INSERT; procedure RETRIEVE (FIRST_ITEM : out ITEM) is ... end; begin -- initialization of the table linkages end TABLE_MANAGER; 7.6 Example of a Text Handling Package This example illustrates a simple text handling package. The users only have access to the visible part; the implementation is hidden from them in the private part and the package body (not shown). From a user's point of view, a TEXT is a variable-length string. Each text object has a maximum length, which must be given when the object is declared, and a current value, which is a string of some length between zero and the maximum. The maximum possible length of a text object is an implementation-defined constant. The package defines first the necessary types, then functions that return some characteristics of objects of the type, then the conversion functions between texts and the predefined CHARACTER and STRING types, and finally some of the standard operations on varying strings. Most operations are overloaded on strings and characters as well as on the type TEXT, in order to minimize the number of explicit conversions the user has to write. package TEXT_HANDLER is MAXIMUM : constant := SOME_VALUE; -- implementation-defined subtype INDEX is INTEGER range 0 .. MAXIMUM; type TEXT(MAXIMUM_LENGTH : INDEX) is limited private; function LENGTH (T : TEXT) return INDEX; function VALUE (T : TEXT) return STRING; function EMPTY (T : TEXT) return BOOLEAN; function TO_TEXT (S : STRING; MAX : INDEX) return TEXT; -- maximum length MAX function TO_TEXT (C : CHARACTER; MAX : INDEX) return TEXT; function TO_TEXT (S : STRING) return TEXT; -- maximum length S'LENGTH function TO_TEXT (C : CHARACTER) return TEXT; function "&" (LEFT : TEXT; RIGHT : TEXT) return TEXT; function "&" (LEFT : TEXT; RIGHT : STRING) return TEXT; function "&" (LEFT : STRING; RIGHT : TEXT) return TEXT; function "&" (LEFT : TEXT; RIGHT : CHARACTER) return TEXT; function "&" (LEFT : CHARACTER; RIGHT : TEXT) return TEXT; function "=" (LEFT : TEXT; RIGHT : TEXT) return BOOLEAN; function "<" (LEFT : TEXT; RIGHT : TEXT) return BOOLEAN; function "<=" (LEFT : TEXT; RIGHT : TEXT) return BOOLEAN; function ">" (LEFT : TEXT; RIGHT : TEXT) return BOOLEAN; function ">=" (LEFT : TEXT; RIGHT : TEXT) return BOOLEAN; procedure SET (OBJECT : in out TEXT; VALUE : in TEXT); procedure SET (OBJECT : in out TEXT; VALUE : in STRING); procedure SET (OBJECT : in out TEXT; VALUE : in CHARACTER); procedure APPEND (TAIL : in TEXT; TO : in out TEXT); procedure APPEND (TAIL : in STRING; TO : in out TEXT); procedure APPEND (TAIL : in CHARACTER; TO : in out TEXT); procedure AMEND (OBJECT : in out TEXT; BY : in TEXT; POSITION : in INDEX); procedure AMEND (OBJECT : in out TEXT; BY : in STRING; POSITION : in INDEX); procedure AMEND (OBJECT : in out TEXT; BY : in CHARACTER; POSITION : in INDEX); -- amend replaces part of the object by the given text, string, or character -- starting at the given position in the object function LOCATE (FRAGMENT : TEXT; WITHIN : TEXT) return INDEX; function LOCATE (FRAGMENT : STRING; WITHIN : TEXT) return INDEX; function LOCATE (FRAGMENT : CHARACTER; WITHIN : TEXT) return INDEX; -- all return 0 if the fragment is not located private type TEXT(MAXIMUM_LENGTH : INDEX) is record POS : INDEX := 0; VALUE : STRING(1 .. MAXIMUM_LENGTH); end record; end TEXT_HANDLER; Example of use of the text handling package: A program opens an output file, whose name is supplied by the string NAME. This string has the form [DEVICE :] [FILENAME [.EXTENSION]] There are standard defaults for device, filename, and extension. The user-supplied name is passed to EXPAND_FILE_NAME as a parameter, and the result is the expanded version, with any necessary defaults added. function EXPAND_FILE_NAME (NAME : STRING) return STRING is use TEXT_HANDLER; DEFAULT_DEVICE : constant STRING := "SY:"; DEFAULT_FILE_NAME : constant STRING := "RESULTS"; DEFAULT_EXTENSION : constant STRING := ".DAT"; MAXIMUM_FILE_NAME_LENGTH : constant INDEX := SOME_APPROPRIATE_VALUE; FILE_NAME : TEXT(MAXIMUM_FILE_NAME_LENGTH); begin SET(FILE_NAME, NAME); if EMPTY(FILE_NAME) then SET(FILE_NAME, DEFAULT_FILE_NAME); end if; if LOCATE(':', FILE_NAME) = 0 then SET(FILE_NAME, DEFAULT_DEVICE & FILE_NAME); end if; if LOCATE('.', FILE_NAME) = 0 then APPEND(DEFAULT_EXTENSION, TO => FILE_NAME); end if; return VALUE(FILE_NAME); end EXPAND_FILE_NAME;