


                                                       Chapter 15
                                                         PACKAGES


PACKAGES ARE WHY ADA EXISTS
_________________________________________________________________

One of the biggest advantages of Ada, over most other programming
languages, is its well defined system of modularization and
separate compilation.  Even though Ada allows separate compilation,
it maintains the strong type checking among the various
compilations by enforcing rules of compilation order and
compatibility checking.  Ada uses separate compilation, but
FORTRAN, as a classic example, uses independent compilation, in
which the various parts are compiled with no knowledge of the other
compilation units with which they will be combined.  As we progress
through this material, and additional material to come later, do
not be discouraged if you find many things to keep in mind when
doing separate compilations.  The rules are not meant to be
roadblocks, but are actually benefits for you when you are working
on a large complex system.



LET'S LOOK AT A PACKAGE
_________________________________________________________________

Examine the file named ADDERPKG.ADA for our      ================
first example of a separately compiled Ada         ADDERPKG.ADA
package.  A package, as the term is used in Ada, ================
refers to a collection of related entities, the
collection being composed of procedures,
functions, variables, constants, types, subtypes, and even other
packages.  In our present example, the package is composed of one
type, and one procedure.



THE SPECIFICATION OF THE PACKAGE
_________________________________________________________________

Lines 4 through 8 define the specification of the package named
AdderPkg, which is actually a very simple package, and purposely
kept simple for illustrative purposes.  The type MY_ARRAY is
defined, as well as the procedure heading for Add_Em_Up in the
specification part of the package.  The only things a user needs
to know about the package in order to use it are defined in the
package specification, so it becomes the interface to the outside
world.  With a few defining statements, this is all the user would
need to know about the package, and he could be kept away from the
actual details of how the procedure does its job.  We will see more
about the topic of information hiding later in this chapter.


                                                        Page 15-1

                                            Chapter 15 - Packages

Note that anything that is declared in the specification part of
the package can be used in any other package that with's this
package.

We have an unconstrained array type declared in line 5 which we
have not yet studied in this tutorial.  The range for the subscript
is defined by the "<>", which is a box that must be filled in later
when we define the actual type.  We will cover this in detail in
the chapter on advanced array topics.



THE BODY OF THE PACKAGE
_________________________________________________________________

Lines 12 through 23 give the body of the package, and it is
distinguished from the specification by the reserved word body in
its header, and by the fact that the procedure is completely
defined here.  Anything defined or declared in the specification
part of the package is available for use here, just as if it were
defined at the beginning of this section.  The procedure header is
redefined here in full, and it must exactly match the definition
in the specification or you will get a compile error and no
compilation.  There is nothing different about this procedure from
any other procedure we have seen, it just happens to be in the
package body.

Note that any types, variables, constants, procedures, or
functions, can be declared in the package body for use within the
body, but none of them are available outside of the package because
they are not defined in the specification part of the package.  The
variable declared in line 15 named Total is not available outside
of this package and there is no way it can be referred to outside
of the package without being declared in the package specification.
In fact, since it is embedded within the procedure, it would be
hidden anyway, but the fact remains that no entities are available
outside of the package except those that are declared in the
specification of the package.

Note that since the array has no defined limits, we must use
attributes to define the loop range.  Even though you may find this
a bit confusing, you will appreciate the flexibility found here
after we study some of the more advanced topics.



IT CAN BE COMPILED BUT NOT EXECUTED
_________________________________________________________________

This file can be compiled, but it cannot be linked and executed
because it is not a complete program, it is only a package
containing a type and a procedure which can be called from another
program just like we have been calling the procedure Put in the
Text_IO package throughout this tutorial.

                                                        Page 15-2

                                            Chapter 15 - Packages


One other point must be made before we look at a program to use
this package, the specification and the body do not need to be in
the same file, they can be contained in separate files and compiled
separately.  If this is the case, the specification must be
compiled prior to compiling the body because the body uses
information generated during compilation of the specification.
Actually, even though they are in one file in this example, they
are considered separately by the compiler, being compiled in serial
fashion.  This file is said to be composed of two compilation
units.



FILENAME VERSUS PACKAGE NAME
_________________________________________________________________

In all of the example programs so far in this tutorial we have used
the same name for the filename and the program name, or the
procedure name.  This is not really necessary, but it was felt that
an additional level of complexity should be delayed until later.
We have arrived at the time when an explanation is needed.  When
Ada compiles a program, it adds the result of the compilation into
its library using the program name.  This library entry includes
all information needed to link the program later with the other
needed library entries.  Later when you use the linker supplied
with your compiler, the linker will collect all of the necessary
compiled packages and subprograms and combine them into an
executable program.

In order to compile a program, it is necessary to give the filename
so the operating system can find the program for the Ada compiler,
but in order to link a program, the filename is no longer of any
use because the name that really matters is the program name, and
the program name is what the linker uses.  Ada allows identifiers
to be of any arbitrary length, but your operating system has some
length limit, eight if you are using MS_DOS, therefore the Ada
compiler may need to somehow make up a new name if intermediate
results are put into individual files.  It will be up to you to
determine how your compiler stores intermediate results and how it
makes up filenames for these results.

For simplicity, therefore, all program names have been limited to
eight characters, and the same name is used for the filename
throughout most of this tutorial.



NOW TO USE THE NEW PACKAGE
_________________________________________________________________

The example file named ADDER1.ADA, illustrates how to use the
previously studied package.  There is nothing different about this
program from any other program we have used except that it uses the

                                                        Page 15-3

                                            Chapter 15 - Packages

package we defined and named AdderPkg, which it  ================
acknowledges in lines 5 and 6 where it tells the    ADDER1.ADA
system to with the package and to use it in the  ================
program at hand.  It also uses the renaming
statement in line 19 which we will discuss
later.  The remainder of the program is simple, and you should have
no trouble deciphering it.  The primary purpose of these two
examples is to illustrate how to write a library package.

In line 17 we declare an array of type MY_ARRAY and at this time
we supply the range limits for the subscript.  You may begin to see
the flexibility in this method of array declaration, but we will
study it in detail later.



THE with CLAUSE
_________________________________________________________________

It is finally time for a complete definition of just what the with
clause does for us.  When we with a package into our program, we
are telling the system that we wish to have everything that is
declared in the specification of that package available for our use
in this program.  Accordingly, the system will look at the items
declared in the specification for that package and every time we
use one of those items, it will see that we have the correct number
of parameters and that we have the types declared for each
parameter correctly.  Note that this happens during compilation and
explains why Ada is said to be compiled separately, but not
independently of other compilation units.  In a sense, the
resources available in the withed package act as though they are
extensions to the Ada programming language.  Because of this, the
with clause is called a context clause.

When you arrive at the linking operation, the withed packages are
automatically added into the executable file, as are any other
packages that are withed by the package you have explicitly told
the system to with into your program.  Note that the package named
STANDARD is automatically withed into every Ada program,
subprogram, or package.  The package named STANDARD defines many
of the predefined entities such as INTEGER, BOOLEAN, FLOAT, etc.

In a large program, it is possible to with the same package several
times since it is used in several packages.  You can be assured
that only one copy of the package will be included during the
linking operation.  Multiple copies will not be stored.

One other point must be made before leaving this topic, and that
is the fact that all with clauses must be at the beginning of the
program or package.  There is a good reason for this.  The
dependent packages, and hence the overall program structure must
be given at the beginning of each package making it easy to
ascertain the overall structure without being forced to search
through the entire listing for each package.

                                                        Page 15-4

                                            Chapter 15 - Packages


THE use CLAUSE
_________________________________________________________________

The use clause in Ada allows you to use a shorthand when naming
procedures, functions, variables, etc, from a package.  Instead of
using the extended naming convention, or the so called "dot"
notation, and including the package name followed by the procedure
name, dotted together, you can simply use the procedure name and
let the system figure out what package it is coming from.  In most
of the programs we have studied so far, we have included the
Text_IO package in a use clause.  If the use clause were omitted
we would have to identify the package in each use of the procedures
used.  Put("This is Ada"); would have to be changed to read
Text_IO.Put("This is Ada");, which clutters up the listing a bit
but removes all ambiguity.

Because it is possible to get a different procedure than the one
you are expecting under very unusual conditions of overloaded
procedure names, the use of the use clause is falling into some
disrepute in the software engineering literature.  Without the use
clause, you are forced to type in additional information for each
procedure call, but it leads to no ambiguity and therefore follows
the basic premise of Ada that a program is written once but read
many times.  The extra keystrokes are worth the trouble to include
them.

Use of the use clause is a matter of personal taste or possibly a
style dictated by a project style guide.



RENAMING A PROCEDURE
_________________________________________________________________

A procedure can be renamed in order to reduce the length of the
identifier, especially if a rather long extended name is required.
It may be better to use a more descriptive name for the actual use
of a generic or general purpose procedure.  The method of renaming
is illustrated in lines 19 and 20 of this program.  Of most
importance is the fact that the entire list of formal parameters
must be repeated.  This is done so that the definition of the new
procedure name is complete and should be of help during program
debugging.

Use of the new name, which is of course only a synonym and not a
new procedure, is illustrated in line 35 of this program.

If you compiled the previous file, you can compile, link, and
execute this one to see that the system knows how to link the two
together.




                                                        Page 15-5

                                            Chapter 15 - Packages

COMBINING FILES
_________________________________________________________________

If you wish, you could combine the two files, provided you appended
the second file to the end of the first.  The compiler would then
compile all three in succession, after which you could link the
results, and execute the result.  The library files must be
compiled first so that the compiler can check the types in the
procedure call to see that they agree, so putting them before the
calling program conforms to this rule.  If you did put them in a
single file, you would still need the statements in lines 5 and 6
to tell the system to with and use the library file defined earlier
in the file, because the compiler would consider them to be three
separate compilations.



ANOTHER METHOD OF COMBINING FILES
_________________________________________________________________

The example program named ADDER2.ADA illustrates ================
another way to combine the last two files, in       ADDER2.ADA
this case including the package in the           ================
declaration part of the program.  The
specification part of the package is in lines
15 through 19, and the body is in lines 27 through 38.  In this
case, a new type is defined between the two parts to illustrate
that it can be done.  Since the package is compiled as a part of
the main program, it does not have to be mentioned in a with
statement.  The compiler knows that it is a part of the program,
but the use must be mentioned to tell the system where to get the
procedure name and the type.  Of course the use can be omitted and
the extended naming convention used for all references to the
package.

Even though the body is defined after the variable New_Array is
declared in line 23, this variable is not directly available for
use in the body, because the package structure effectively builds
a strong wall around the enclosed statements, and nothing can get
in or out.  The only inputs to and outputs from the body are those
defined in the specification part of the package.  Of course the
variable New_Array is available to the procedure because it is
passed in as a parameter, but is not directly visible.

One other difference occurs here that is different from the last
two files.  This embedded package is not available for use by any
other program, because it is enclosed within this program, and is
not therefore a library package.  The entire file contains only one
compilation unit.






                                                        Page 15-6

                                            Chapter 15 - Packages

ORDER OF DECLARATIONS
_________________________________________________________________

This is a fine point, but a very important point if you get a
compile error that you do not understand.  If you were allowed to
include a variable declaration after you declare a procedure, it
is possible for the tiny variable declaration to get lost, or at
least hard to find in the listing.  The designers of Ada decided
to force you to put the little things first and the bigger things
last by making a rule that says, "No variable, constant, type, or
subtype can be declared in any declaration block following the
declaration of a procedure, function or package body."  It may be
an unnecessary rule, but it does exist and is checked by all
validated Ada compilers.
You should compile and execute this program and you will see that
it truly is identical to the previous two files combined.


ANOTHER KIND OF SEPARATE COMPILATION
_________________________________________________________________

The example file named ADDER3.ADA illustrates    ================
still another method of separate compilation.       ADDER3.ADA
This program is identical to the last except     ================
that the package body is removed to a separate
file for separate compilation, and is called a
stub.  The statement in line 27 indicates to the compiler that the
body will be found elsewhere.  Although this illustrates separate
compilation of a package body, the same method can be used for
separate compilation of a procedure.  This could be used if you
wished to remove a large procedure from the logic defined here to
make it more manageable.

The separately compiled body is found in the     ================
file named ADDERSTB.ADA, which begins with the     ADDERSTB.ADA
reserved word separate which indicates that this ================
is a stub.  The main program, or whatever other
package, procedure, or function, that uses this
stub is defined in parentheses following the reserved word separate
to tell the compiler where this is used.  This stub cannot be
called or used by any other program, because it is in truth part
of the program Adder3, not a general purpose program.  Any
variables, types, procedures, etc, that are available for use at
the point where the stub is used, are available at the point where
the stub is defined.  The stub therefore has the same environment
as the environment existing at the point of use, in this case line
27 of ADDER3.ADA.


ORDER OF COMPILATION FOR THE STUB
_________________________________________________________________

Since all of the variables, types, etc must be made available to
the stub, the using program must be compiled before the stub itself

                                                        Page 15-7

                                            Chapter 15 - Packages

is compiled.  After both are compiled, the program can be linked
and executed.  You should compile ADDER3.ADA first, then
ADDERSTB.ADA should be compiled, and finally ADDER3 should be
linked.  You will then have an executable ADDER3 program.



ORDER OF COMPILATION IS NOT MYSTERIOUS
_________________________________________________________________

The example files included with this chapter are intended to
illustrate to you the required order of compilation in a meaningful
way, not as a group of rules to be memorized.  If you understand
the dependencies of files on one another, the order of compilation
will make sense, and you will be able to intelligently arrange your
programs to use the Ada type checking between the various
separately compiled files.  Remember that Ada, unlike Pascal, was
designed to allow the development of huge programs that require
separate compilation facilities, and yet retain the strong type
checking between modules.



A PACKAGE WITH AN INITIALIZATION PART
_________________________________________________________________

The example file named ADDER4.ADA illustrates    ================
one more feature of a package.  This program is     ADDER4.ADA
nearly identical to the first program in this    ================
chapter.  Both files which comprise the first
example program have been incorporated into a
single file for ease of compilation, and the variable named Total
has been made global within the package.  Since it is global within
the package, it can be referred to by any subprogram in the package
or in the initialization section as illustrated in lines 23 and 24.
This section is optional but can be included in any package.

Note that the initialization section is only executed once, at load
time.  For that reason, this program will not operate exactly as
the first one did.  The result that is output is identical in both
cases, but the additional calls will not produce the same result
because the variable Total is not cleared to zero during each call
in this example program as it is in the first example.  The
initialization section only initializes the variable once, and it
is impossible to call this section of code from within the
executable part of the package.









                                                        Page 15-8

                                            Chapter 15 - Packages

PROGRAMMING EXERCISES
_________________________________________________________________

1.   Remove the package body from ADDER2.ADA and make it a stub.
     Compile the two resulting files in the correct order and link
     and execute the resulting program.

2.   Remove all use clauses from the program named FORMATS.ADA in
     the last chapter, and prefix the I/O procedure calls with the
     proper package names.  It should be clear to you that there
     can be no naming conflicts after this is done.

3.   Change the name of the two compilation units in ADDERPKG.ADA
     without modifying the filename, and modify ADDER1.ADA to
     correspond to the new package name.  Use a name that contains
     more characters than your operating system permits for a
     filename.  Compile each file and link them together to result
     in an executable program.



































                                                        Page 15-9