home *** CD-ROM | disk | FTP | other *** search
-
-
-
- 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