DataMuseum.dk

Presents historical artifacts from the history of:

Rational R1000/400 Tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about Rational R1000/400 Tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: C T

⟦19b3517de⟧ TextFile

    Length: 38043 (0x949b)
    Types: TextFile
    Names: »CHAPTER_7«

Derivation

└─⟦180fe333a⟧ Bits:30000405 8mm tape, Rational 1000, SW CATALOG, 10_20_0
└─⟦180fe333a⟧ Bits:30000537 8mm tape, Rational 1000, SW Catalog 10_20_0
    └─⟦5cb1d1d7f⟧ »DATA« 
        └─⟦3b1ee7bd8⟧ 
            └─⟦this⟧ 

TextFile

                                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


                                   7 - 1








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.


















































                                   7 - 2








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;


                                   7 - 3








       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;

















































                                   7 - 4








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


                                   7 - 5








body (see 3.9).
























































                                   7 - 6









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;



                                   7 - 7









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 - 8












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





                                   7 - 9








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.


















































                                  7 - 10








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 - 11











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.














































                                  7 - 12








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.



                                  7 - 13








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.















































                                  7 - 14










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


                                  7 - 15








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 - 16








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.




                                  7 - 17








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.










































                                  7 - 18








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:




                                  7 - 19








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.



















































                                  7 - 20








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 => ' ');



                                  7 - 21








       procedure INSERT  (NEW_ITEM   : in  ITEM);
       procedure RETRIEVE(FIRST_ITEM : out ITEM);

       TABLE_FULL : exception;  --  raised by INSERT when table full
    end;




















































                                  7 - 22








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.



                                  7 - 23








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.



















































                                  7 - 24








    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;


                                  7 - 25








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;

















                                  7 - 26