


                                                       Chapter 28
                                              GENERIC SUBPROGRAMS


GENERIC UNITS ADD TO ADA'S FLEXIBILITY
_________________________________________________________________

The concept of packages along with generic units gives Ada the
capability to be used for general purpose software components.
Utility routines can be written once and used in several programs
eliminating the need to rewrite and debug the utility again and
again.  This ability would be greatly diminished without the
generic concept in Ada.


WHAT IS A GENERIC UNIT?
_________________________________________________________________

A generic unit is a template for a subprogram or ================
a package, and cannot be executed directly.  A     SWAPSOME.ADA
copy of the generic unit can be instantiated,    ================
and the resulting unit can be executed just as
any other subprogram or package.  As with all
other topics in this course, the best way to learn how to use this
new technique is through use of an example, so examine the program
named SWAPSOME.ADA.


A SIMPLE GENERIC PROCEDURE
_________________________________________________________________

The generic specification is given in lines 2 through 4 and the
generic body is given in lines 6 through 12.  A careful inspection
of this procedure will reveal that there is no actual type defined
for the type listed as type ITEM.  The purpose of using a generic
procedure is to allow you to use the procedure for any type you
desire, within reasonable limits, without being forced to rewrite
the procedure for each specific type.  In order to use this
procedure in a program, we will supply a type which will be
substituted in the procedure each place where the type ITEM appears
when we instantiate a copy of the procedure.

The reserved word generic is used to mark the beginning of a
generic unit, which may be a package, a procedure, or a function.
Between the reserved words, in this case generic and procedure, we
include a list of formal generic parameters which define the
optional types, variables, and other entities which will be used
in the body of the procedure.  In this case there is only one
formal generic parameter named ITEM, and it is constrained to be
any type of the integer class of types.  An explanation will be
given soon to define why the type of ITEM is constrained to be of
the integer class of types.  For the time being, simply accept the
statement as true.

                                                        Page 28-1

                                 Chapter 28 - Generic Subprograms


The procedure specification in line 4 and the procedure body in
lines 6 through 12 are no different than any of the other
procedures we have used throughout this tutorial, except for the
fact that the type named ITEM is undefined throughout the
procedure.  Since the type ITEM is undefined, the procedure is
unusable in its present form.



HOW DO WE USE THE GENERIC PROCEDURE?
_________________________________________________________________

In order to use the generic procedure, we must first tell the
system to get a copy of it which we do in line 16 using the with
clause.

Referring to the main program, we declare a derived type of the
integer class named MY_INT in line 25.  In line 27 we declare a
procedure named SwapInt and because of the reserved word new being
used after the declaration, it is defining an instantiation of the
generic package named Exchange_Data.  You will recall that
instantiating the procedure means we create an instance of the
generic procedure.

The type INTEGER is used in the resulting executable procedure each
time the generic word ITEM is used in the original generic
procedure.  The result would be exactly the same as making a copy
of the generic procedure, changing its name to SwapInt, then
substituting the type INTEGER for each appearance of the word ITEM.
A call to SwapInt with any two INTEGER type variables will result
in exchanging their values.



WHAT GOOD DID THIS DO US?
_________________________________________________________________

Admittedly, we could have simply defined the procedure SwapInt in
the first place and everything would have been just fine.  The real
benefit comes from the next line of the program where we
instantiate another copy of the generic procedure named
Exchange_Data, name it SwapNew, and tell the system to use the type
MY_INT as the replacement for the formal generic type named ITEM.
Line 28 is therefore equivalent to writing out the generic
procedure once again for the new type we declared earlier.

If we had a large number of different types of the integer class
of variables, we could instantiate a copy of this procedure for
each with a single line for each, so the benefit would be very
significant.




                                                        Page 28-2

                                 Chapter 28 - Generic Subprograms

REUSABLE SOFTWARE
_________________________________________________________________

Once this procedure is written and debugged, it can be used in any
number of programs because it does not have to be modified for each
new type we make up.  Different programmers can use the procedure
in different packages once it is tested thoroughly, so each
programmer does not have to write it anew.  There is presently a
new industry developing in the software community.  This industry
specializes in writing reusable software components in Ada that are
written with the flexibility afforded by the generic units.

The remainder of the program should pose no problem for your
understanding, so you will be left on your own to study it, then
compile and execute it.



A FEW NOTES ABOUT GENERIC UNITS
_________________________________________________________________

This program could be split into two separate files with the first
including the generic procedure in lines 1 through 12, and the
second including the using program in lines 14 through 57.  The
files can be compiled separately, and once the generic procedure
has been compiled, it never needs to be compiled again, but will
be included in the Ada library in compiled form.  The generic
procedure and the main program were combined here for the sake of
convenience.



ANOTHER NOTE ON COMPILATION UNITS
_________________________________________________________________

In some cases, the generic part can be split once again into two
separate files, the first being the generic specification in lines
2 through 4 and the other being the procedure body in lines 6
through 12.  If they are split in this manner, the order of
compilation must be maintained so that the type checking can be
done as described earlier in this tutorial.  The Ada definition
allows a compiler writer to require the generic specification and
body be included in the same file for his convenience, so it
depends on the particular compiler you are using to define whether
or not you can split the generic procedure into two parts.

Of course, with such a simple procedure, it is difficult to grasp
the magnitude of the benefits of this new Ada construct, but in a
real programming situation, many cases of reusability will become
apparent and the benefits will be appreciated.





                                                        Page 28-3

                                 Chapter 28 - Generic Subprograms

ADDITIONAL FORMAL GENERIC TYPES
_________________________________________________________________

Examine the program named SWAPMORE.ADA for two   ================
additional examples of generic subprograms.  You   SWAPMORE.ADA
will notice that the first is a generic          ================
procedure and the second is a generic function,
indicating to you that either form of subprogram
can be written as a generic unit.  The first subprogram is nearly
identical to the one in the last example program, the only
difference being in the declaration of the formal generic type in
line 3 which we will discuss shortly.  The second subprogram, the
function in lines 16 through 25, will be simple for you to
comprehend if you substitute, in your mind, the type INTEGER for
each occurrence of the type ANOTHER_ITEM.  In fact, it averages the
two values given to it and returns the result.


WHY THE DIFFERENT TYPES?
_________________________________________________________________

In line 3, we declare the type ITEM as private, and in the function
named Average we declare the type ANOTHER_ITEM as a type of the
integer class of types (we will show you how shortly, just be a
little patient).  As with so many things, the type selected is the
result of a compromise.  If we restrict the type to only the
integer class, then in the generic subprogram, we can perform any
operations that are defined for the integer class of variables,
such as arithmetic operations, all six comparisons, and logical
operations.  On the other hand, we are restricted in the number of
types that the generic subprogram can be used for, since it cannot
be used for any real types, records, or arrays.  In a sense, we
have restricted the usage of the generic procedure, by allowing
more freedom of use within the procedure.

The first subprogram declares the formal generic type to be of type
private which severely limits the operations that can be performed
on the data within the procedure.  The generic procedure is limited
to assignment, and compares for equality and inequality.  No other
operations are allowed within the generic procedure.  However, by
limiting the type to private within the generic procedure, we allow
a much greater flexibility in the calling program.  This generic
procedure can be instantiated with any type that can be assigned
or compared for equality or inequality, which is essentially any
type.  By limiting the operations allowed within the generic
procedure, we have made it much more usable to the caller.


HOW FLEXIBLE ARE THE GENERIC SUBPROGRAMS?
_________________________________________________________________

Jumping ahead to the main program for a few moments, we see that
the generic procedure Exchange_Data is successfully instantiated
for the type INTEGER, MY_RECORD, and FLOAT, in addition to a few

                                                        Page 28-4

                                 Chapter 28 - Generic Subprograms

others.  This procedure is extremely flexible because it was
declared with a very restrictive (restrictive within the generic
procedure itself) generic formal type.  In addition, it makes sense
to be able to swap two elements of record types, or two integers,
or two real variables.

Continuing in the main program, you will see in lines 62 and 63
that there are not nearly as many uses for the function which was
declared with the much more liberal (liberal within the generic
function itself) type.  Since arithmetic operations on integers
were permitted in the function, a record type cannot be used in an
instantiation of this generic procedure, because it makes no sense
to add two records together.


A SEEMINGLY UNNECESSARY LIMITATION
_________________________________________________________________

You will note that because of the way we declared the generic
formal type, real types cannot be used in an instantiation of the
function.  It would make sense to be able to take the average of
two real numbers, but it cannot be done with this function because
of the definition of Ada.  The reason is because there is no
generalized scalar type that can be of either integer or real.  The
addition of one would add lots of extra baggage to the language and
would not add much to the utility of Ada.  The language is already
big enough without adding another burden to it.


AN INEFFICIENT THING TO DO
_________________________________________________________________

Lines 57 through 60 each instantiate a copy of the generic
procedure Exchange_Data, and each uses the same type for its
instantiation, namely CHARACTER.  This will result in four sections
of code that each do the same thing, the only difference being in
the name by which the procedure will be called.  If there is in
fact a basis for using different names for the same procedure the
renaming facility should be used because it will only create an
alias for each new name.  Only one section of code will be
required.


A REALLY DUMB THING TO DO
_________________________________________________________________

Line 64 contains an instantiation of the generic function Average
that uses type INTEGER and names it Swap, a name that has already
been overloaded five times in lines 53 through 57.  The Ada system
is smart enough to figure out what you really want to do by
comparing types and recognizing the fact that this is a function
call, and it will do exactly what you want it to do.  It would be
very poor practice to use a nondescriptive name for a function in
any Ada program, but it would be especially bad to use a name that

                                                        Page 28-5

                                 Chapter 28 - Generic Subprograms

has already been used for a different purpose.  The Ada compiler
would handle this correctly, but you could have a really hard time
deciphering it later.

As discussed earlier, this file could be separated into at least
three different files and compiled separately, and with some
compilers, it could be separated into five files.


A QUICK REVIEW
_________________________________________________________________

Remember that when selecting the types for the generic formal
parameters, if you select a type that is very restrictive within
the subprogram, the subprogram can be used with many types by the
user.  If you select a type that is rather permissive within the
subprogram, the resulting generic subprogram cannot be used with
as many types by the user.  Be sure to compile and execute this
program after you understand the details of its operation.



WHAT ARE THE FORMAL GENERIC TYPES?
_________________________________________________________________

Examine the program named ALLGENER.ADA for an    ================
example of nearly all of the available formal      ALLGENER.ADA
generic types.  We will study each one in        ================
succession in some amount of detail.  Beginning
with the limited private type illustrated in
line 3, we have no freedom within the subprogram, but it can be
used with any type in the calling program.  The private type is
very limited within the generic subprogram, but allows nearly any
type in the calling program.



THE DISCRETE FORMAL PARAMETER TYPE
_________________________________________________________________

The discrete formal parameter type is declared with the reserved
word type followed by the type name, the reserved word is, and the
box "<>" within parentheses as illustrated.  The type name used
here can be matched with any actual type which is of a discrete
class.  These types are integer class types, enumeration types, the
BOOLEAN, and the CHARACTER type.  Within the generic subprogram,
any operation can be used which can be done to an enumerated
variable.  This explains why it was necessary for the POS and ORD
attributes to be defined for integer type variables as mentioned
in an earlier lesson.  Because these attributes are available, the
integer types can be used with this formal generic type.




                                                        Page 28-6

                                 Chapter 28 - Generic Subprograms

THE INTEGER CLASS FORMAL PARAMETER TYPE
_________________________________________________________________

The integer formal parameter type, as illustrated in line 16, is
declared with the reserved word type followed by the type name, the
reserved words is and range, and the "box" as illustrated.  The
type name used here can be matched with any actual type that is of
the integer class.  Within the generic subprogram, the arithmetic
operations are available, in addition to all of those operations
available with the discrete generic formal parameter.  But as you
may expect, a generic subprogram using this generic formal
parameter can not be instantiated with an enumerated type.


THE REAL FORMAL PARAMETER TYPES
_________________________________________________________________

The real formal parameter types are declared as illustrated in
lines 7 and 8, with the reserved words digits or delta indicating
the floating or fixed variety of real types.  Only operations
permitted for those types are permitted within the generic
subprogram, and only the respective real types can be used by the
calling program when instantiating a copy of the generic unit.

The first procedure simply lists all of the above mentioned generic
formal parameters, but uses none for any purpose.  The second
procedure lists all of the types in a similar manner but declares
a procedure that uses all six for formal parameters as an
illustration.  The program itself uses little of the declared
interface.  Only the type INT_TYPE is exercised in the program
where it is used in a type transformation statement.

The details of this program will be left for your study after which
you should compile it.  Because this is composed of only generic
subprograms, it is not executable.


THE ARRAY TYPE FORMAL GENERIC PARAMETER
_________________________________________________________________

Examine the program named ARRAYGEN.ADA for       ================
examples of array type generic formal              ARRAYGEN.ADA
parameters.  The specification and body of a     ================
procedure with a constrained array type generic
formal parameter are given in lines 3 through
17.  There are actually three generic formal parameters listed
here, one new one on each of the three lines numbered 4 through 6.

To define how this procedure is used, we will refer to the
instantiation call in line 49 of this file which happens to be
within the declaration part of the main program.  The generic
formal name SUBSCRIPT must be replaced with an actual parameter
that is of any discrete type because the type mark contains a "<>"
in parentheses.  Furthermore, the first element in the actual

                                                        Page 28-7

                                 Chapter 28 - Generic Subprograms

parameter list will be substituted for this parameter because it
is first in the formal parameter list.  To begin our instantiation
requested in line 49, we can replace every occurrence of the word
SUBSCRIPT in lines 4 through 17 with the word LIMIT_RANGE and we
are on our way to creating a usable procedure.

The second parameter of the actual parameter list is the type named
MY_FLOAT, and it will be used to replace every occurrence of the
generic formal type named FLOAT_TYPE listed in the second line of
the generic formal parameters.  You will notice that the required
type is any floating point type because of the occurrence of the
reserved word digits in line 5.  The type of the actual parameter,
as listed in line 50, and defined in line 46 is a floating point
type.  The types therefore match up and the statement in lines 49
and 50 will pass the strong type checking done by the Ada compiler.


CONSTRAINED ARRAY GENERIC PARAMETER
_________________________________________________________________

The third line of the formal parameters, which is line 6, declares
the constrained array with which a given instantiation can be used.
You will notice that this formal parameter depends on both formal
parameters declared previously, but since there is only one new
parameter in this line, the Ada compiler can properly assign the
actual type LITTLE_FLOAT as the replacement for the formal
parameter named CONSTRAINED_ARRAY.  If you actually make a copy of
this generic procedure, and replace the formal parameters with
their corresponding actual parameters, then change the name of the
procedure to Sum_Array, you could replace the instantiation in
lines 49 and 50 with the resulting procedure and the program
operation would be identical.  Of course you would have a problem
of declaring a procedure body prior to some smaller declarations,
but that could be easily fixed.  Lines 64 and 65 give examples of
using the instantiated procedure and will be left to your study.


UNCONSTRAINED ARRAY GENERIC PARAMETER
_________________________________________________________________

Lines 22 through 34 give an example of use of an unconstrained
array as a generic formal parameter, and is nearly identical to the
last example except that the index type is declared to be of type
POSITIVE rather than being flexible as in the last example.  The
type of the index variable could be declared as a generic type
parameter with another line added prior to line 24, and the
instantiating statement would require three types instead of only
two.  Line 60 is the example instantiating statement and lines 67
and 68 give examples of use of the resulting function.

As mentioned several times before, each of these subprograms could
be separated into separate files and compiled separately, then used
by any calling program.  Be sure to compile and execute this
program.

                                                        Page 28-8

                                 Chapter 28 - Generic Subprograms


THE ACCESS FORMAL GENERIC PARAMETER
_________________________________________________________________

Examine the program named ACCESGEN.ADA for our   ================
first look at the last generic formal parameter    ACCESGEN.ADA
type, the access type.  The first procedure, in  ================
lines 2 through 14 use an access type that
matches only an access type which accesses an
INTEGER, resulting in little or no flexibility since an access type
to an INTEGER type variable is used infrequently.  A copy of this
generic procedure is instantiated in line 45 of the main program,
and the procedure is exercised in line 76 as an example for your
study.
The second procedure, given in lines 19 through 32 illustrates a
much more useful procedure because this procedure can be used for
any access type, including the composite types of arrays and
records.  Three copies of the generic procedure are instantiated
in lines 64 through 68 and all three are exercised in the main
program.  Note that the more general procedure is used in line 77
to transpose the INTEGER type variables back to their original
positions.

The details of this program should be simple for you to follow, so
no additional comment needs to be made.  Be sure to compile and
execute this program.


PROGRAMMING EXERCISES
_________________________________________________________________

1.   Add a subtype of INTEGER to SWAPSOME.ADA and determine what
     happens if you instantiate a copy of Exchange_Data for the
     subtype in addition to the instantiation for INTEGER.  Add
     statements to the main program to swap values of the new type.

2.   Attempt to instantiate a copy of Average that uses type FLOAT
     in SWAPSOME.ADA.

3.   Attempt to perform an addition in the body of Exchange_Data
     in violation of the private type.












                                                        Page 28-9