



                                                       Chapter 29
                                                 GENERIC PACKAGES



OUR FIRST GENERIC PACKAGE
_________________________________________________________________

In the last chapter we studied the use of generic subprograms.
This chapter will be devoted to the study of generic packages, and
we will exhaust the topic because only procedures, functions, and
packages can be used as generic units.

Examine the file named GENPKG.ADA for our first  ================
example of a generic package.  This package is      GENPKG.ADA
named EasyPkg, because it is so easy to          ================
understand, and is composed of one procedure and
one function.  The generic package begins with
the reserved word generic, followed by two generic formal
parameters, and the standard format for an Ada package
specification in lines 5 through 9.  The first generic formal
parameter is a discrete type, and the second is a floating point
type as we discussed in the last chapter.

The instantiating statements are given in lines 39 and 41 of the
main program and are no different than those used in the last
chapter except for the first word, the reserved word package,
because we are declaring an instance of a package in this case.
If you replace the formal parameter types with the types declared
in each instantiation statement, you will have a normal package
just as we studied previously.  In the case of a package, we can
add the use clause as we have in lines 40 and 42, eliminating the
need for the extended naming notation, commonly called the dot
notation.  After declaring a few variables to work with, we are
ready to exercise the two procedures and functions we have
declared.  It should be clear to you that we have a procedure and
a function in the package named Funny_Stuff, and another procedure
and function in the package named Usual_Stuff.

A fine point must be mentioned about the use clause when used with
the generic package.  It is not legal to use a use clause with the
generic package itself.  Every instantiation must explicitly give
the extended name for the generic package.  Of course this only
occurs with nested generic packages which are the topic of the next
example program.  The use clause however, is legal for use with any
and every instantiated copy of a generic package.  The instantiated
package's new name cannot be overloaded because it is not permitted
to overload the name of any package.





                                                        Page 29-1

                                    Chapter 29 - Generic Packages

USING THE INSTANTIATED PACKAGES
_________________________________________________________________

In line 53, we call the procedure named Trade_Values, but since
there are two procedures with this name, Ada will pick the correct
one by comparing the types.  This is our old friend called
overloading again.  In line 54, because of the types used, the
other procedure will be used as indicated in the comments.  In
lines 55 and 56, we explicitly tell the system which overloading
to use, but it will still check the types to see if they are
compatible.  In line 57 we tell the system to use the wrong one
which leads to a type mismatch and a compile error, and in line 58,
we use two different types for the parameters, which is another
type mismatch.  (Lines 57 and 58 are commented out so that we will
not actually get the error, but you should remove the comments to
see that the compiler does report an error.)

Lines 60 through 64 give examples of proper usage of the two
functions instantiated above and illustrate that the literals of
type universal_real are compatible with both copies of the function
as you would expect.  The compiler uses the type of the assignment
variable on the left hand side of the assignment statement to
decide which overloading to use for each statement.

After you spend enough time to understand this program, compile and
execute it even though it has no output.



NESTED GENERIC PACKAGES
_________________________________________________________________

The example program named NESTPKG.ADA contains    ===============
a generic package nested within another             NESTPKG.ADA
non-generic package.  The outer package contains  ===============
a single procedure, and the nested generic
package contains a single formal generic
parameter of a floating point type, and a single function.  The
procedure and function are the same as those in the last program,
but they are organized differently here for illustration.

Note carefully that since the procedure is not in the generic part
of the outer package, it is directly available in the same manner
as if it were in a package without a generic part.  The package
name can be declared in a use clause which will make the
non-generic portion of the package usable.  This is not really too
new to you because the Text_IO package we have been using
throughout this tutorial contains several nested generic packages.
The procedure to Put a string, as well as the procedures named
Put_Line and New_Line are in the non-generic part of the package,
and the procedures to output variables are nested in generic parts.
It would be beneficial for you to take a look at the package named
Text_IO in section 14.3.10 of the LRM.  Spending a few minutes
studying that package at this time will be time well spent.

                                                        Page 29-2

                                    Chapter 29 - Generic Packages


The executable part of the program is very simple and very similar
to the last example program so it will be left to the student to
study, compile, and execute this program.



OBJECTS AS GENERIC FORMAL PARAMETERS
_________________________________________________________________

Examine the program named OBJGEN.ADA for an      ================
example of using objects for formal generic         OBJGEN.ADA
parameters instead of just types.  In this case  ================
the number of ROWS and the number of COLUMNS
will be part of the instantiation, and the
resulting procedure and function will be ready to work with the
desired size matrices.  In addition, the constant named ROWS, and
the constant named COLUMNS are initialized to the values given in
lines 4 and 5.  If a value is not given with the instantiation,
these values will be used in much the same way that we use default
values with a procedure or function.

In this case, the package body uses the standard Text_IO package
and outputs a string to the monitor each time one of the
subprograms is called.  This is only done to illustrate to you that
there is nothing magic about the package Text_IO, and that it can
be used within another package.



USING THE OBJECTS
_________________________________________________________________

In line 58, the package is instantiated using the positional
aggregate notation with values of 3 and 5 for the matrix size.
Line 60 illustrates the use of the defaults declared in the generic
part above, and line 61 illustrates the use of the named aggregate
notation used during package instantiation.



AN EXPORTED TYPE CAN BE USED
_________________________________________________________________

Referring back to line 8, we have the type named LOCAL_MATRIX
declared in the package specification and therefore available to
any calling program.  If you refer to the private part of the
package specification, you will see that the type LOCAL_MATRIX is
declared to be a function of the formal generic objects.  After we
instantiate a copy of the package, we have the exported type
available for use in the calling program.  We use the types
exported in lines 66 through 68 to declare a few variables, but
even though two of the instantiations make use of the use clause,
we must explicitly declare the desired type by using the extended

                                                        Page 29-3

                                    Chapter 29 - Generic Packages

naming notation.  This is because the compiler has no way of
knowing which exported type we are interested in using for each
variable.

With the above descriptions of the new concepts in this program,
you should be able to understand the details of it.  Be sure to
compile and execute this program.



A PROCEDURE AS A GENERIC PARAMETER
_________________________________________________________________

Examine the program named PROCPKG.ADA for an      ===============
example of a procedure being used as a generic      PROCPKG.ADA
formal parameter.  The syntax uses the reserved   ===============
word with to begin the formal parameter in line
4, and the complete header for the procedure is
given with the list of formal parameters and their types.  This
procedure can then be called from within the body of the package
and will refer to a procedure that is actually outside of the
generic package.  Now we must define the procedure that will be
called in order to satisfy a call to this formal parameter.  We
will see where this procedure is defined shortly.

Refer to the main program where the procedure named R_Average is
declared.  It has exactly the same formal parameter structure as
that declared in the generic formal parameter, so it can be used
in the instantiating call in line 40.  A call to the procedure in
the generic instantiation actually results in a call back to the
procedure in the calling program to do some calculations.



WHAT CAN THIS BE USED FOR?
_________________________________________________________________

This capability gives you the ability to write a generic package
that can be used in several places but with a slight difference in
each place, because each instantiation can use a different
procedure for the reference back to the calling program.  This is
simply another one of the available entities that add to the
flexibility of Ada.  After you understand the logic here, you
should compile and execute this program.



A FUNCTION AS A GENERIC PARAMETER
_________________________________________________________________

Examine the program named FUNCPKG.ADA for an example of using a
function as a generic formal parameter.  The logic is similar to
that described in the last program except that a function is used
for the reference back to the calling program.  No further

                                                        Page 29-4

                                    Chapter 29 - Generic Packages

explanation will be given since it should not be  ===============
needed.  It should not come as much of a            FUNCPKG.ADA
surprise to you that several procedures or        ===============
functions, or a combination of them, can be used
as generic formal parameters.  Any of the
isolated examples can be combined as needed to achieve the desired
goal.  Nesting of generic and normal packages can be done as
needed.  It will be up to you to decide how to modularize and
package your program to best accomplish the stated goals.  Ada
gives you many options.  Be sure to compile and execute this
program.



PROGRAMMING EXERCISES
_________________________________________________________________

1.   Add an enumerated type to GENPKG.ADA, instantiate a copy of
     EasyPkg, and use it to swap some values of the enumerated
     type.  You will have to supply a floating point type with the
     enumerated type when you instantiate it.

2.   Convert CHARSTAK.ADA from chapter 16 of this tutorial into a
     generic package that can be used with any discrete type.
     Modify TRYSTAK.ADA from the same chapter to instantiate and
     use both an enumerated type and an INTEGER type.



























                                                        Page 29-5