home *** CD-ROM | disk | FTP | other *** search
/ Chip 1995 March / CHIP3.mdf / programm / prog3 / chap18.txt < prev    next >
Encoding:
Text File  |  1991-07-01  |  17.2 KB  |  410 lines

  1.  
  2.  
  3.  
  4.                                                        Chapter 18
  5.                                        ADVANCED SUBPROGRAM TOPICS
  6.  
  7.  
  8. In part 1 of this tutorial we covered the topic of subprograms in
  9. some detail, but there are many other things to discuss about them,
  10. so we return to them for more advanced topics.
  11.  
  12.  
  13.  
  14. DEFAULT PARAMETERS
  15. _________________________________________________________________
  16.  
  17. Examine the program named DEFAULTS.ADA for some  ================
  18. examples of default parameters used in the         DEFAULTS.ADA
  19. definition of a procedure.  The procedure has    ================
  20. four formal parameters, of which the first is of
  21. mode in out, and the other three are of the mode
  22. in.  The three in parameters have default values of zero assigned
  23. to each of them.  When we call this procedure, we are not required
  24. to supply a value for each variable, and those we do not supply a
  25. value for will be defaulted to zero upon execution.  Of course the
  26. first variable in the list, named Total, must have a variable name
  27. supplied so it can return a value.  Therefore, it cannot be
  28. defaulted.
  29.  
  30. The procedure itself, and the first two calls to it, in lines 32
  31. and 33, should pose no problem for you to understand.  When we
  32. arrive at line 34, however, we have a few things to point out.
  33.  
  34.  
  35.  
  36. NAMED NOTATION FOR ACTUAL PARAMETERS
  37. _________________________________________________________________
  38.  
  39. We are using the named aggregate notation for the actual parameters
  40. in line 34, so they can be listed in any order, but due to the
  41. defaults defined in the procedure header, we do not have to specify
  42. every parameter, allowing the default values to take effect upon
  43. a call to the procedure.  You will see, when you compile and run
  44. this program, that Cows and Pigs will have the default values of
  45. zero.  Lines 35 and 36 also use the named aggregate notation and
  46. should be clear as to their operation.  Line 37 uses the mixed
  47. aggregate notation, and as we discussed before, the positional
  48. aggregate notation can be used initially, but after switching to
  49. the named notation, all remaining entries must be named, unless
  50. they are allowed to default.  Line 38 illustrates the degenerate
  51. case where only the result is used, with all three input variables
  52. defaulting to zero.
  53.  
  54.  
  55.  
  56.  
  57.  
  58.                                                         Page 18-1
  59.  
  60.                           Chapter 18 - Advanced Subprogram Topics
  61.  
  62. PARAMETERS WITH out MODE CANNOT BE DEFAULTED
  63. _________________________________________________________________
  64.  
  65. Since the parameters that are of either mode in out or mode out
  66. must be able to return a value, they must have a variable defined
  67. as their actual parameter, and cannot therefore be defaulted.
  68.  
  69. Default parameters are not new to you, because you have actually
  70. used them in procedure calls before.  When you call the procedure
  71. New_Line, you have an optional number following it as in
  72. New_Line(2).  The number of lines to space up on the monitor is
  73. defaulted to one in the package Text_IO, which was supplied to you
  74. with your compiler, but you can override the default by inserting
  75. a value for the number of lines.  It is defined in section 14.3.10
  76. of the LRM, where the formal parameter named Spacing is defaulted
  77. to the value of 1.  Refer to either your documentation or the LRM
  78. and see this in use.
  79.  
  80. One other point must be made before you compile and execute this
  81. program.  The formal parameter named Total, must be of mode in out
  82. rather than just mode out because we refer to it in the Put
  83. procedure call, where we effectively read its value.
  84.  
  85.  
  86.  
  87. DYNAMIC DEFAULT PARAMETERS
  88. _________________________________________________________________
  89.  
  90. The program named DEFAULT2.ADA is identical to   ================
  91. the last example program except for one detail.    DEFAULT2.ADA
  92. The definition of the default values of the      ================
  93. formal parameters are declared differently here.
  94. You will notice that the default values are not
  95. only arithmetic combinations, but the values to combine are the
  96. results of function calls, where the values are dynamically
  97. evaluated each time the procedure Animals is called.  The default
  98. values are constants for each call of the procedure, but they are
  99. evaluated for each call and could therefore be different each time
  100. the procedure is called.  As mentioned previously, this is called
  101. elaboration.  If the return from Cow_Constant, in line 15, returned
  102. the value of a global variable for example, the main program could
  103. modify the value of the global variable and therefore modify the
  104. value of the default variables prior to each call to the procedure.
  105. It would therefore be possible to set up different default values
  106. in each of several different procedures based on the currently read
  107. time of day, the ambient temperature, or whatever other variable
  108. conditions could be read into the system.
  109.  
  110. Be sure to compile and run this program and observe the results,
  111. comparing them with the results you expected the program to output.
  112.  
  113.  
  114.  
  115.  
  116.  
  117.                                                         Page 18-2
  118.  
  119.                           Chapter 18 - Advanced Subprogram Topics
  120.  
  121. THE MYSTERY OF RECURSION
  122. _________________________________________________________________
  123.  
  124. This topic will be no problem for the            ================
  125. experienced Pascal programmer, but for the         RECURSON.ADA
  126. FORTRAN programmer, it may be an entirely new    ================
  127. and somewhat perplexing topic.  Stay with it,
  128. and you will see exactly what recursion is and
  129. how to use it effectively.  Examine the example program named
  130. RECURSON.ADA, which is the simplest recursive program possible, but
  131. which is excellent for describing what recursion is and how it
  132. works.
  133.  
  134. Beginning at the main program we assign the variable named Index
  135. the value of 7 then call the procedure named Print_And_Decrement,
  136. taking along the value of Index as an actual parameter.  Arriving
  137. at the procedure itself, we use the name Value for the formal
  138. parameter, and we display the value on the monitor with an
  139. appropriate line of text.  Continuing on to line 18, we decrement
  140. the value of the passed variable then compare the result to zero.
  141. If the value is greater than zero, we call the procedure named
  142. Print_And_Decrement taking along the newly decremented value called
  143. New_Value.  Here is where the FORTRAN programmer notices something
  144. new.  We are calling the procedure from within itself, and that is
  145. just what recursion is.  Assume for a moment that we call another
  146. complete copy of the procedure, decrement the value once again, and
  147. if it is still not zero, call another copy of the procedure.
  148. Eventually, the value of the passed variable will be reduced to
  149. zero and the procedure calls will all be completed, each returning
  150. to the procedure that called it until we arrive once again at the
  151. main program.
  152.  
  153. You should compile and run this program to see that it really does
  154. what we say it does, then return for additional discussion of this
  155. program and what it is doing.
  156.  
  157. This is a really dumb way to count from 7 down to 1, but it is a
  158. very simple way to illustrate the use of recursion.  Later in this
  159. tutorial, we will have illustrations of excellent uses of recursion
  160. for your instruction.
  161.  
  162.  
  163. WHAT ACTUALLY HAPPENED?
  164. _________________________________________________________________
  165.  
  166. When we called the procedure Print_And_Decrement, it began by
  167. elaborating its formal variables and assigning them the values
  168. passed by the calling program.  These are stored on the stack, an
  169. internal portion of memory set aside by the Ada system to store
  170. dynamic variables and constants, and are available for later use.
  171. The local variables are then generated and elaborated, although in
  172. this case there was only one, and stored on the stack also with
  173. means to refer to them.  Finally, the program code itself is
  174. actually executed, and when it is completed, the local variables
  175.  
  176.                                                         Page 18-3
  177.  
  178.                           Chapter 18 - Advanced Subprogram Topics
  179.  
  180. and formal variables are erased from the stack and no longer exist.
  181. In a recursive call, the stack grows with each new call, and when
  182. control returns to an earlier call of the code, the variables for
  183. that call are still on the stack and available for use.  In the
  184. previous program, we actually had only one copy of the executable
  185. code stored, but had many copies of the formal variable stored on
  186. the stack.
  187.  
  188.  
  189.  
  190. ALL ADA SUBPROGRAMS ARE RE-ENTRANT
  191. _________________________________________________________________
  192.  
  193. If you have experience in systems programming and understand what
  194. it means for a program to be re-entrant, you will understand how
  195. this means of variable storage allows all Ada subprograms to be re-
  196. entrant.  The LRM requires that all Ada subprograms be re-entrant,
  197. but if you don't know what it means, don't worry about it.
  198.  
  199. It would be a good exercise for you to insert some code to display
  200. the value of the formal parameter following the recursive call to
  201. see that the value of the formal variable is still available when
  202. we return from each recursive call.  This code would be inserted
  203. immediately after line 21.
  204.  
  205. You should spend the time necessary to completely understand this
  206. program before continuing on to the next example program.
  207.  
  208.  
  209.  
  210. A RECURSIVE FUNCTION
  211. _________________________________________________________________
  212.  
  213. Examine the program named FUNCRECR.ADA for an    ================
  214. example of a recursive function, which is          FUNCRECR.ADA
  215. actually no different than a recursive           ================
  216. procedure.  This program is used to illustrate
  217. two other Ada concepts, neither of which is new
  218. to you, but both of which contain valuable insights for you.  The
  219. first is the partial declaration which will be discussed at the
  220. outset, and the other is a return to exceptions which will be
  221. deferred for a couple of paragraphs.
  222.  
  223.  
  224.  
  225. THE PARTIAL DECLARATION
  226. _________________________________________________________________
  227.  
  228. Ada requires that you define everything prior to its use, and this
  229. rule is never broken.  Suppose you wished to have a program with
  230. two procedures, two functions, or even a procedure and a function,
  231. calling each other recursively.  If A were declared first, it could
  232. be called by B, but A could not call B because it would not be
  233. defined by the time A was elaborated, and we cannot break the rule
  234.  
  235.                                                         Page 18-4
  236.  
  237.                           Chapter 18 - Advanced Subprogram Topics
  238.  
  239. of defining everything prior to its use.  This is more properly
  240. called linear declaration.  Ada gets around this by allowing a
  241. partial declaration of a type, procedure, function, or package.
  242. If you remember, we used the partial declaration with respect to
  243. a record when we studied the access type variable, so this concept
  244. is not entirely new to you.  It is also proper to refer to the
  245. partial declaration as a function specification.
  246.  
  247. In the present example program, we desire to place the functions
  248. in the program in the order shown, for no good reason other than
  249. to illustrate that it can be done, but we have the problem of
  250. linear declaration because Factorial calls Factorial_Possible.  The
  251. partial declaration in line 14 tells the system that the function
  252. Factorial_Possible will be defined later and what its
  253. characteristics will be, because the formal parameter is defined
  254. along with its return type.  The function Factorial is then
  255. completely defined, followed by the complete definition of the
  256. function Factorial_Possible and we have accomplished our desired
  257. goals, while meeting the requirements of linear declaration.
  258.  
  259.  
  260.  
  261. NOW FOR THE RECURSIVE FUNCTION
  262. _________________________________________________________________
  263.  
  264. Assuming you are familiar with the factorial function which is a
  265. part of higher mathematics, we will continue with the program
  266. description.  Since Factorial(N) is the same as N times
  267. Factorial(N-1), we can calculate the factorial of any number using
  268. a recursive technique.  We continue to recurse until we reach a
  269. point where we need the value of Factorial(1), which we define as
  270. 1, and begin going back up the recursive chain, each time
  271. multiplying by the value with which we entered into that particular
  272. recursive call.  By defining the value of Factorial(0) as 1, and
  273. making it illegal to take the factorial of any negative number, we
  274. can now write the complete program.  Most of the program involves
  275. checking limits and outputting messages, but the actual work is
  276. done by line 29 which is the recursive call as defined earlier in
  277. this paragraph.
  278.  
  279.  
  280.  
  281. EXTRA CHECKS ARE DONE
  282. _________________________________________________________________
  283.  
  284. The program should not be at all difficult for you to follow and
  285. understand, so you will be left on your own to study it.  A few
  286. comments on style should be mentioned, however.  The function
  287. Factorial calls the other function to verify that the value is
  288. factoriable before attempting to do so, and the main program, in
  289. lines 46 through 56, checks the value before calling the function
  290. to attempt to factorialize the number.  This is not necessarily
  291. bad, because the procedure was written to be all inclusive, and the
  292. main program may wish to do something entirely different than that
  293.  
  294.                                                         Page 18-5
  295.  
  296.                           Chapter 18 - Advanced Subprogram Topics
  297.  
  298. dictated by the procedure.  In lines 60 through 65 however, the
  299. main program accepts the default error handling provided by the
  300. procedure, by calling the procedure without first checking the
  301. data.
  302.  
  303. Compile and run this program, observing the various messages output
  304. depending on which portion of the program handled the errors.  Note
  305. carefully that the program is not meant to be an illustration of
  306. good programming style, only as an illustration of a few things
  307. that can be done using Ada.
  308.  
  309.  
  310.  
  311. ANOTHER LOOK AT EXCEPTIONS
  312. _________________________________________________________________
  313.  
  314. The last program was unusual because it has the ability to
  315. illustrate four of the five standard exceptions defined by the Ada
  316. system.  They can be illustrated as follows;
  317.  
  318. Program_Error - Remove the return from line 29 and you will drop
  319.      out of the bottom of the function.  (Actually, a validated
  320.      compiler will generate a compile error.)
  321.  
  322. Constraint_Error - Change the type of the formal parameter in line
  323.      16 to POSITIVE, which covers the range of all numbers legal
  324.      to compute a factorial for. Then call the function with -1 as
  325.      a parameter.
  326.  
  327. Storage_Error - Call Factorial(100000).  The stack will overflow
  328.      prior to completing the required number of recursions.
  329.  
  330. Numeric_Error - Call Factorial(35).  The resultant factorial should
  331.      overflow the allowed range of INTEGER.
  332.  
  333.  
  334.  
  335. A FUNCTION RETURNING AN ARRAY
  336. _________________________________________________________________
  337.  
  338. The example program named REVERS.ADA will give   ================
  339. you an example of a function that returns more      REVERS.ADA
  340. than a single scalar variable, in fact, it       ================
  341. returns an entire array of INTEGER type
  342. variables.  The program itself is extremely
  343. simple, the only thing that is different from most functions is the
  344. type of return listed in line 15, and the actual return in line 21.
  345. These must, of course, agree in type or a type mismatch error will
  346. be issued during compilation.
  347.  
  348. Using the technique given here, there is no reason why a function
  349. cannot return a record, or even an array of records, as long as the
  350. types are correctly defined and they agree when used.
  351.  
  352.  
  353.                                                         Page 18-6
  354.  
  355.                           Chapter 18 - Advanced Subprogram Topics
  356.  
  357.  
  358. THE INLINE pragma
  359. _________________________________________________________________
  360.  
  361. A pragma is a compiler directive, as we have mentioned previously,
  362. and the INLINE pragma tells the compiler to expand the called
  363. subprogram body and insert it into the calling program for each
  364. call.  Since the code is inserted inline, there is no calling
  365. sequence and therefore no time wasted in setting up subprogram
  366. linkage, but there is a separate section of code for each
  367. invocation of the subprogram.  The result will probably be a larger
  368. but faster program.  Use of this pragma is illustrated as follows;
  369.  
  370.      pragma INLINE(subprogram1, subprogram2, ... );
  371.  
  372. This line is inserted in the declarative part of the compilation
  373. unit, following the subprogram specifications.  By definition, the
  374. meaning of a subprogram is not affected by the pragma.
  375.  
  376.  
  377.  
  378. PROGRAMMING EXERCISES
  379. _________________________________________________________________
  380.  
  381. 1.   As suggested earlier, include an output statement in
  382.      RECURSON.ADA to display the value of Value after the recursive
  383.      call to see the recursion come back up through the chain of
  384.      recursive calls.
  385.  
  386. 2.   Write a recursive program with two procedures named Increment
  387.      and Display which call each other and increment a variable,
  388.      initialized to 1, until it reaches a count of 8.
  389.  
  390.  
  391.  
  392.  
  393.  
  394.  
  395.  
  396.  
  397.  
  398.  
  399.  
  400.  
  401.  
  402.  
  403.  
  404.  
  405.  
  406.  
  407.  
  408.  
  409.  
  410.                                                         Page 18-7