


                                                       Chapter 18
                                       ADVANCED SUBPROGRAM TOPICS


In part 1 of this tutorial we covered the topic of subprograms in
some detail, but there are many other things to discuss about them,
so we return to them for more advanced topics.



DEFAULT PARAMETERS
_________________________________________________________________

Examine the program named DEFAULTS.ADA for some  ================
examples of default parameters used in the         DEFAULTS.ADA
definition of a procedure.  The procedure has    ================
four formal parameters, of which the first is of
mode in out, and the other three are of the mode
in.  The three in parameters have default values of zero assigned
to each of them.  When we call this procedure, we are not required
to supply a value for each variable, and those we do not supply a
value for will be defaulted to zero upon execution.  Of course the
first variable in the list, named Total, must have a variable name
supplied so it can return a value.  Therefore, it cannot be
defaulted.

The procedure itself, and the first two calls to it, in lines 32
and 33, should pose no problem for you to understand.  When we
arrive at line 34, however, we have a few things to point out.



NAMED NOTATION FOR ACTUAL PARAMETERS
_________________________________________________________________

We are using the named aggregate notation for the actual parameters
in line 34, so they can be listed in any order, but due to the
defaults defined in the procedure header, we do not have to specify
every parameter, allowing the default values to take effect upon
a call to the procedure.  You will see, when you compile and run
this program, that Cows and Pigs will have the default values of
zero.  Lines 35 and 36 also use the named aggregate notation and
should be clear as to their operation.  Line 37 uses the mixed
aggregate notation, and as we discussed before, the positional
aggregate notation can be used initially, but after switching to
the named notation, all remaining entries must be named, unless
they are allowed to default.  Line 38 illustrates the degenerate
case where only the result is used, with all three input variables
defaulting to zero.





                                                        Page 18-1

                          Chapter 18 - Advanced Subprogram Topics

PARAMETERS WITH out MODE CANNOT BE DEFAULTED
_________________________________________________________________

Since the parameters that are of either mode in out or mode out
must be able to return a value, they must have a variable defined
as their actual parameter, and cannot therefore be defaulted.

Default parameters are not new to you, because you have actually
used them in procedure calls before.  When you call the procedure
New_Line, you have an optional number following it as in
New_Line(2).  The number of lines to space up on the monitor is
defaulted to one in the package Text_IO, which was supplied to you
with your compiler, but you can override the default by inserting
a value for the number of lines.  It is defined in section 14.3.10
of the LRM, where the formal parameter named Spacing is defaulted
to the value of 1.  Refer to either your documentation or the LRM
and see this in use.

One other point must be made before you compile and execute this
program.  The formal parameter named Total, must be of mode in out
rather than just mode out because we refer to it in the Put
procedure call, where we effectively read its value.



DYNAMIC DEFAULT PARAMETERS
_________________________________________________________________

The program named DEFAULT2.ADA is identical to   ================
the last example program except for one detail.    DEFAULT2.ADA
The definition of the default values of the      ================
formal parameters are declared differently here.
You will notice that the default values are not
only arithmetic combinations, but the values to combine are the
results of function calls, where the values are dynamically
evaluated each time the procedure Animals is called.  The default
values are constants for each call of the procedure, but they are
evaluated for each call and could therefore be different each time
the procedure is called.  As mentioned previously, this is called
elaboration.  If the return from Cow_Constant, in line 15, returned
the value of a global variable for example, the main program could
modify the value of the global variable and therefore modify the
value of the default variables prior to each call to the procedure.
It would therefore be possible to set up different default values
in each of several different procedures based on the currently read
time of day, the ambient temperature, or whatever other variable
conditions could be read into the system.

Be sure to compile and run this program and observe the results,
comparing them with the results you expected the program to output.





                                                        Page 18-2

                          Chapter 18 - Advanced Subprogram Topics

THE MYSTERY OF RECURSION
_________________________________________________________________

This topic will be no problem for the            ================
experienced Pascal programmer, but for the         RECURSON.ADA
FORTRAN programmer, it may be an entirely new    ================
and somewhat perplexing topic.  Stay with it,
and you will see exactly what recursion is and
how to use it effectively.  Examine the example program named
RECURSON.ADA, which is the simplest recursive program possible, but
which is excellent for describing what recursion is and how it
works.

Beginning at the main program we assign the variable named Index
the value of 7 then call the procedure named Print_And_Decrement,
taking along the value of Index as an actual parameter.  Arriving
at the procedure itself, we use the name Value for the formal
parameter, and we display the value on the monitor with an
appropriate line of text.  Continuing on to line 18, we decrement
the value of the passed variable then compare the result to zero.
If the value is greater than zero, we call the procedure named
Print_And_Decrement taking along the newly decremented value called
New_Value.  Here is where the FORTRAN programmer notices something
new.  We are calling the procedure from within itself, and that is
just what recursion is.  Assume for a moment that we call another
complete copy of the procedure, decrement the value once again, and
if it is still not zero, call another copy of the procedure.
Eventually, the value of the passed variable will be reduced to
zero and the procedure calls will all be completed, each returning
to the procedure that called it until we arrive once again at the
main program.

You should compile and run this program to see that it really does
what we say it does, then return for additional discussion of this
program and what it is doing.

This is a really dumb way to count from 7 down to 1, but it is a
very simple way to illustrate the use of recursion.  Later in this
tutorial, we will have illustrations of excellent uses of recursion
for your instruction.


WHAT ACTUALLY HAPPENED?
_________________________________________________________________

When we called the procedure Print_And_Decrement, it began by
elaborating its formal variables and assigning them the values
passed by the calling program.  These are stored on the stack, an
internal portion of memory set aside by the Ada system to store
dynamic variables and constants, and are available for later use.
The local variables are then generated and elaborated, although in
this case there was only one, and stored on the stack also with
means to refer to them.  Finally, the program code itself is
actually executed, and when it is completed, the local variables

                                                        Page 18-3

                          Chapter 18 - Advanced Subprogram Topics

and formal variables are erased from the stack and no longer exist.
In a recursive call, the stack grows with each new call, and when
control returns to an earlier call of the code, the variables for
that call are still on the stack and available for use.  In the
previous program, we actually had only one copy of the executable
code stored, but had many copies of the formal variable stored on
the stack.



ALL ADA SUBPROGRAMS ARE RE-ENTRANT
_________________________________________________________________

If you have experience in systems programming and understand what
it means for a program to be re-entrant, you will understand how
this means of variable storage allows all Ada subprograms to be re-
entrant.  The LRM requires that all Ada subprograms be re-entrant,
but if you don't know what it means, don't worry about it.

It would be a good exercise for you to insert some code to display
the value of the formal parameter following the recursive call to
see that the value of the formal variable is still available when
we return from each recursive call.  This code would be inserted
immediately after line 21.

You should spend the time necessary to completely understand this
program before continuing on to the next example program.



A RECURSIVE FUNCTION
_________________________________________________________________

Examine the program named FUNCRECR.ADA for an    ================
example of a recursive function, which is          FUNCRECR.ADA
actually no different than a recursive           ================
procedure.  This program is used to illustrate
two other Ada concepts, neither of which is new
to you, but both of which contain valuable insights for you.  The
first is the partial declaration which will be discussed at the
outset, and the other is a return to exceptions which will be
deferred for a couple of paragraphs.



THE PARTIAL DECLARATION
_________________________________________________________________

Ada requires that you define everything prior to its use, and this
rule is never broken.  Suppose you wished to have a program with
two procedures, two functions, or even a procedure and a function,
calling each other recursively.  If A were declared first, it could
be called by B, but A could not call B because it would not be
defined by the time A was elaborated, and we cannot break the rule

                                                        Page 18-4

                          Chapter 18 - Advanced Subprogram Topics

of defining everything prior to its use.  This is more properly
called linear declaration.  Ada gets around this by allowing a
partial declaration of a type, procedure, function, or package.
If you remember, we used the partial declaration with respect to
a record when we studied the access type variable, so this concept
is not entirely new to you.  It is also proper to refer to the
partial declaration as a function specification.

In the present example program, we desire to place the functions
in the program in the order shown, for no good reason other than
to illustrate that it can be done, but we have the problem of
linear declaration because Factorial calls Factorial_Possible.  The
partial declaration in line 14 tells the system that the function
Factorial_Possible will be defined later and what its
characteristics will be, because the formal parameter is defined
along with its return type.  The function Factorial is then
completely defined, followed by the complete definition of the
function Factorial_Possible and we have accomplished our desired
goals, while meeting the requirements of linear declaration.



NOW FOR THE RECURSIVE FUNCTION
_________________________________________________________________

Assuming you are familiar with the factorial function which is a
part of higher mathematics, we will continue with the program
description.  Since Factorial(N) is the same as N times
Factorial(N-1), we can calculate the factorial of any number using
a recursive technique.  We continue to recurse until we reach a
point where we need the value of Factorial(1), which we define as
1, and begin going back up the recursive chain, each time
multiplying by the value with which we entered into that particular
recursive call.  By defining the value of Factorial(0) as 1, and
making it illegal to take the factorial of any negative number, we
can now write the complete program.  Most of the program involves
checking limits and outputting messages, but the actual work is
done by line 29 which is the recursive call as defined earlier in
this paragraph.



EXTRA CHECKS ARE DONE
_________________________________________________________________

The program should not be at all difficult for you to follow and
understand, so you will be left on your own to study it.  A few
comments on style should be mentioned, however.  The function
Factorial calls the other function to verify that the value is
factoriable before attempting to do so, and the main program, in
lines 46 through 56, checks the value before calling the function
to attempt to factorialize the number.  This is not necessarily
bad, because the procedure was written to be all inclusive, and the
main program may wish to do something entirely different than that

                                                        Page 18-5

                          Chapter 18 - Advanced Subprogram Topics

dictated by the procedure.  In lines 60 through 65 however, the
main program accepts the default error handling provided by the
procedure, by calling the procedure without first checking the
data.

Compile and run this program, observing the various messages output
depending on which portion of the program handled the errors.  Note
carefully that the program is not meant to be an illustration of
good programming style, only as an illustration of a few things
that can be done using Ada.



ANOTHER LOOK AT EXCEPTIONS
_________________________________________________________________

The last program was unusual because it has the ability to
illustrate four of the five standard exceptions defined by the Ada
system.  They can be illustrated as follows;

Program_Error - Remove the return from line 29 and you will drop
     out of the bottom of the function.  (Actually, a validated
     compiler will generate a compile error.)

Constraint_Error - Change the type of the formal parameter in line
     16 to POSITIVE, which covers the range of all numbers legal
     to compute a factorial for. Then call the function with -1 as
     a parameter.

Storage_Error - Call Factorial(100000).  The stack will overflow
     prior to completing the required number of recursions.

Numeric_Error - Call Factorial(35).  The resultant factorial should
     overflow the allowed range of INTEGER.



A FUNCTION RETURNING AN ARRAY
_________________________________________________________________

The example program named REVERS.ADA will give   ================
you an example of a function that returns more      REVERS.ADA
than a single scalar variable, in fact, it       ================
returns an entire array of INTEGER type
variables.  The program itself is extremely
simple, the only thing that is different from most functions is the
type of return listed in line 15, and the actual return in line 21.
These must, of course, agree in type or a type mismatch error will
be issued during compilation.

Using the technique given here, there is no reason why a function
cannot return a record, or even an array of records, as long as the
types are correctly defined and they agree when used.


                                                        Page 18-6

                          Chapter 18 - Advanced Subprogram Topics


THE INLINE pragma
_________________________________________________________________

A pragma is a compiler directive, as we have mentioned previously,
and the INLINE pragma tells the compiler to expand the called
subprogram body and insert it into the calling program for each
call.  Since the code is inserted inline, there is no calling
sequence and therefore no time wasted in setting up subprogram
linkage, but there is a separate section of code for each
invocation of the subprogram.  The result will probably be a larger
but faster program.  Use of this pragma is illustrated as follows;

     pragma INLINE(subprogram1, subprogram2, ... );

This line is inserted in the declarative part of the compilation
unit, following the subprogram specifications.  By definition, the
meaning of a subprogram is not affected by the pragma.



PROGRAMMING EXERCISES
_________________________________________________________________

1.   As suggested earlier, include an output statement in
     RECURSON.ADA to display the value of Value after the recursive
     call to see the recursion come back up through the chain of
     recursive calls.

2.   Write a recursive program with two procedures named Increment
     and Display which call each other and increment a variable,
     initialized to 1, until it reaches a count of 8.





















                                                        Page 18-7