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

  1.  
  2.  
  3.  
  4.                                                        Chapter 28
  5.                                               GENERIC SUBPROGRAMS
  6.  
  7.  
  8. GENERIC UNITS ADD TO ADA'S FLEXIBILITY
  9. _________________________________________________________________
  10.  
  11. The concept of packages along with generic units gives Ada the
  12. capability to be used for general purpose software components.
  13. Utility routines can be written once and used in several programs
  14. eliminating the need to rewrite and debug the utility again and
  15. again.  This ability would be greatly diminished without the
  16. generic concept in Ada.
  17.  
  18.  
  19. WHAT IS A GENERIC UNIT?
  20. _________________________________________________________________
  21.  
  22. A generic unit is a template for a subprogram or ================
  23. a package, and cannot be executed directly.  A     SWAPSOME.ADA
  24. copy of the generic unit can be instantiated,    ================
  25. and the resulting unit can be executed just as
  26. any other subprogram or package.  As with all
  27. other topics in this course, the best way to learn how to use this
  28. new technique is through use of an example, so examine the program
  29. named SWAPSOME.ADA.
  30.  
  31.  
  32. A SIMPLE GENERIC PROCEDURE
  33. _________________________________________________________________
  34.  
  35. The generic specification is given in lines 2 through 4 and the
  36. generic body is given in lines 6 through 12.  A careful inspection
  37. of this procedure will reveal that there is no actual type defined
  38. for the type listed as type ITEM.  The purpose of using a generic
  39. procedure is to allow you to use the procedure for any type you
  40. desire, within reasonable limits, without being forced to rewrite
  41. the procedure for each specific type.  In order to use this
  42. procedure in a program, we will supply a type which will be
  43. substituted in the procedure each place where the type ITEM appears
  44. when we instantiate a copy of the procedure.
  45.  
  46. The reserved word generic is used to mark the beginning of a
  47. generic unit, which may be a package, a procedure, or a function.
  48. Between the reserved words, in this case generic and procedure, we
  49. include a list of formal generic parameters which define the
  50. optional types, variables, and other entities which will be used
  51. in the body of the procedure.  In this case there is only one
  52. formal generic parameter named ITEM, and it is constrained to be
  53. any type of the integer class of types.  An explanation will be
  54. given soon to define why the type of ITEM is constrained to be of
  55. the integer class of types.  For the time being, simply accept the
  56. statement as true.
  57.  
  58.                                                         Page 28-1
  59.  
  60.                                  Chapter 28 - Generic Subprograms
  61.  
  62.  
  63. The procedure specification in line 4 and the procedure body in
  64. lines 6 through 12 are no different than any of the other
  65. procedures we have used throughout this tutorial, except for the
  66. fact that the type named ITEM is undefined throughout the
  67. procedure.  Since the type ITEM is undefined, the procedure is
  68. unusable in its present form.
  69.  
  70.  
  71.  
  72. HOW DO WE USE THE GENERIC PROCEDURE?
  73. _________________________________________________________________
  74.  
  75. In order to use the generic procedure, we must first tell the
  76. system to get a copy of it which we do in line 16 using the with
  77. clause.
  78.  
  79. Referring to the main program, we declare a derived type of the
  80. integer class named MY_INT in line 25.  In line 27 we declare a
  81. procedure named SwapInt and because of the reserved word new being
  82. used after the declaration, it is defining an instantiation of the
  83. generic package named Exchange_Data.  You will recall that
  84. instantiating the procedure means we create an instance of the
  85. generic procedure.
  86.  
  87. The type INTEGER is used in the resulting executable procedure each
  88. time the generic word ITEM is used in the original generic
  89. procedure.  The result would be exactly the same as making a copy
  90. of the generic procedure, changing its name to SwapInt, then
  91. substituting the type INTEGER for each appearance of the word ITEM.
  92. A call to SwapInt with any two INTEGER type variables will result
  93. in exchanging their values.
  94.  
  95.  
  96.  
  97. WHAT GOOD DID THIS DO US?
  98. _________________________________________________________________
  99.  
  100. Admittedly, we could have simply defined the procedure SwapInt in
  101. the first place and everything would have been just fine.  The real
  102. benefit comes from the next line of the program where we
  103. instantiate another copy of the generic procedure named
  104. Exchange_Data, name it SwapNew, and tell the system to use the type
  105. MY_INT as the replacement for the formal generic type named ITEM.
  106. Line 28 is therefore equivalent to writing out the generic
  107. procedure once again for the new type we declared earlier.
  108.  
  109. If we had a large number of different types of the integer class
  110. of variables, we could instantiate a copy of this procedure for
  111. each with a single line for each, so the benefit would be very
  112. significant.
  113.  
  114.  
  115.  
  116.  
  117.                                                         Page 28-2
  118.  
  119.                                  Chapter 28 - Generic Subprograms
  120.  
  121. REUSABLE SOFTWARE
  122. _________________________________________________________________
  123.  
  124. Once this procedure is written and debugged, it can be used in any
  125. number of programs because it does not have to be modified for each
  126. new type we make up.  Different programmers can use the procedure
  127. in different packages once it is tested thoroughly, so each
  128. programmer does not have to write it anew.  There is presently a
  129. new industry developing in the software community.  This industry
  130. specializes in writing reusable software components in Ada that are
  131. written with the flexibility afforded by the generic units.
  132.  
  133. The remainder of the program should pose no problem for your
  134. understanding, so you will be left on your own to study it, then
  135. compile and execute it.
  136.  
  137.  
  138.  
  139. A FEW NOTES ABOUT GENERIC UNITS
  140. _________________________________________________________________
  141.  
  142. This program could be split into two separate files with the first
  143. including the generic procedure in lines 1 through 12, and the
  144. second including the using program in lines 14 through 57.  The
  145. files can be compiled separately, and once the generic procedure
  146. has been compiled, it never needs to be compiled again, but will
  147. be included in the Ada library in compiled form.  The generic
  148. procedure and the main program were combined here for the sake of
  149. convenience.
  150.  
  151.  
  152.  
  153. ANOTHER NOTE ON COMPILATION UNITS
  154. _________________________________________________________________
  155.  
  156. In some cases, the generic part can be split once again into two
  157. separate files, the first being the generic specification in lines
  158. 2 through 4 and the other being the procedure body in lines 6
  159. through 12.  If they are split in this manner, the order of
  160. compilation must be maintained so that the type checking can be
  161. done as described earlier in this tutorial.  The Ada definition
  162. allows a compiler writer to require the generic specification and
  163. body be included in the same file for his convenience, so it
  164. depends on the particular compiler you are using to define whether
  165. or not you can split the generic procedure into two parts.
  166.  
  167. Of course, with such a simple procedure, it is difficult to grasp
  168. the magnitude of the benefits of this new Ada construct, but in a
  169. real programming situation, many cases of reusability will become
  170. apparent and the benefits will be appreciated.
  171.  
  172.  
  173.  
  174.  
  175.  
  176.                                                         Page 28-3
  177.  
  178.                                  Chapter 28 - Generic Subprograms
  179.  
  180. ADDITIONAL FORMAL GENERIC TYPES
  181. _________________________________________________________________
  182.  
  183. Examine the program named SWAPMORE.ADA for two   ================
  184. additional examples of generic subprograms.  You   SWAPMORE.ADA
  185. will notice that the first is a generic          ================
  186. procedure and the second is a generic function,
  187. indicating to you that either form of subprogram
  188. can be written as a generic unit.  The first subprogram is nearly
  189. identical to the one in the last example program, the only
  190. difference being in the declaration of the formal generic type in
  191. line 3 which we will discuss shortly.  The second subprogram, the
  192. function in lines 16 through 25, will be simple for you to
  193. comprehend if you substitute, in your mind, the type INTEGER for
  194. each occurrence of the type ANOTHER_ITEM.  In fact, it averages the
  195. two values given to it and returns the result.
  196.  
  197.  
  198. WHY THE DIFFERENT TYPES?
  199. _________________________________________________________________
  200.  
  201. In line 3, we declare the type ITEM as private, and in the function
  202. named Average we declare the type ANOTHER_ITEM as a type of the
  203. integer class of types (we will show you how shortly, just be a
  204. little patient).  As with so many things, the type selected is the
  205. result of a compromise.  If we restrict the type to only the
  206. integer class, then in the generic subprogram, we can perform any
  207. operations that are defined for the integer class of variables,
  208. such as arithmetic operations, all six comparisons, and logical
  209. operations.  On the other hand, we are restricted in the number of
  210. types that the generic subprogram can be used for, since it cannot
  211. be used for any real types, records, or arrays.  In a sense, we
  212. have restricted the usage of the generic procedure, by allowing
  213. more freedom of use within the procedure.
  214.  
  215. The first subprogram declares the formal generic type to be of type
  216. private which severely limits the operations that can be performed
  217. on the data within the procedure.  The generic procedure is limited
  218. to assignment, and compares for equality and inequality.  No other
  219. operations are allowed within the generic procedure.  However, by
  220. limiting the type to private within the generic procedure, we allow
  221. a much greater flexibility in the calling program.  This generic
  222. procedure can be instantiated with any type that can be assigned
  223. or compared for equality or inequality, which is essentially any
  224. type.  By limiting the operations allowed within the generic
  225. procedure, we have made it much more usable to the caller.
  226.  
  227.  
  228. HOW FLEXIBLE ARE THE GENERIC SUBPROGRAMS?
  229. _________________________________________________________________
  230.  
  231. Jumping ahead to the main program for a few moments, we see that
  232. the generic procedure Exchange_Data is successfully instantiated
  233. for the type INTEGER, MY_RECORD, and FLOAT, in addition to a few
  234.  
  235.                                                         Page 28-4
  236.  
  237.                                  Chapter 28 - Generic Subprograms
  238.  
  239. others.  This procedure is extremely flexible because it was
  240. declared with a very restrictive (restrictive within the generic
  241. procedure itself) generic formal type.  In addition, it makes sense
  242. to be able to swap two elements of record types, or two integers,
  243. or two real variables.
  244.  
  245. Continuing in the main program, you will see in lines 62 and 63
  246. that there are not nearly as many uses for the function which was
  247. declared with the much more liberal (liberal within the generic
  248. function itself) type.  Since arithmetic operations on integers
  249. were permitted in the function, a record type cannot be used in an
  250. instantiation of this generic procedure, because it makes no sense
  251. to add two records together.
  252.  
  253.  
  254. A SEEMINGLY UNNECESSARY LIMITATION
  255. _________________________________________________________________
  256.  
  257. You will note that because of the way we declared the generic
  258. formal type, real types cannot be used in an instantiation of the
  259. function.  It would make sense to be able to take the average of
  260. two real numbers, but it cannot be done with this function because
  261. of the definition of Ada.  The reason is because there is no
  262. generalized scalar type that can be of either integer or real.  The
  263. addition of one would add lots of extra baggage to the language and
  264. would not add much to the utility of Ada.  The language is already
  265. big enough without adding another burden to it.
  266.  
  267.  
  268. AN INEFFICIENT THING TO DO
  269. _________________________________________________________________
  270.  
  271. Lines 57 through 60 each instantiate a copy of the generic
  272. procedure Exchange_Data, and each uses the same type for its
  273. instantiation, namely CHARACTER.  This will result in four sections
  274. of code that each do the same thing, the only difference being in
  275. the name by which the procedure will be called.  If there is in
  276. fact a basis for using different names for the same procedure the
  277. renaming facility should be used because it will only create an
  278. alias for each new name.  Only one section of code will be
  279. required.
  280.  
  281.  
  282. A REALLY DUMB THING TO DO
  283. _________________________________________________________________
  284.  
  285. Line 64 contains an instantiation of the generic function Average
  286. that uses type INTEGER and names it Swap, a name that has already
  287. been overloaded five times in lines 53 through 57.  The Ada system
  288. is smart enough to figure out what you really want to do by
  289. comparing types and recognizing the fact that this is a function
  290. call, and it will do exactly what you want it to do.  It would be
  291. very poor practice to use a nondescriptive name for a function in
  292. any Ada program, but it would be especially bad to use a name that
  293.  
  294.                                                         Page 28-5
  295.  
  296.                                  Chapter 28 - Generic Subprograms
  297.  
  298. has already been used for a different purpose.  The Ada compiler
  299. would handle this correctly, but you could have a really hard time
  300. deciphering it later.
  301.  
  302. As discussed earlier, this file could be separated into at least
  303. three different files and compiled separately, and with some
  304. compilers, it could be separated into five files.
  305.  
  306.  
  307. A QUICK REVIEW
  308. _________________________________________________________________
  309.  
  310. Remember that when selecting the types for the generic formal
  311. parameters, if you select a type that is very restrictive within
  312. the subprogram, the subprogram can be used with many types by the
  313. user.  If you select a type that is rather permissive within the
  314. subprogram, the resulting generic subprogram cannot be used with
  315. as many types by the user.  Be sure to compile and execute this
  316. program after you understand the details of its operation.
  317.  
  318.  
  319.  
  320. WHAT ARE THE FORMAL GENERIC TYPES?
  321. _________________________________________________________________
  322.  
  323. Examine the program named ALLGENER.ADA for an    ================
  324. example of nearly all of the available formal      ALLGENER.ADA
  325. generic types.  We will study each one in        ================
  326. succession in some amount of detail.  Beginning
  327. with the limited private type illustrated in
  328. line 3, we have no freedom within the subprogram, but it can be
  329. used with any type in the calling program.  The private type is
  330. very limited within the generic subprogram, but allows nearly any
  331. type in the calling program.
  332.  
  333.  
  334.  
  335. THE DISCRETE FORMAL PARAMETER TYPE
  336. _________________________________________________________________
  337.  
  338. The discrete formal parameter type is declared with the reserved
  339. word type followed by the type name, the reserved word is, and the
  340. box "<>" within parentheses as illustrated.  The type name used
  341. here can be matched with any actual type which is of a discrete
  342. class.  These types are integer class types, enumeration types, the
  343. BOOLEAN, and the CHARACTER type.  Within the generic subprogram,
  344. any operation can be used which can be done to an enumerated
  345. variable.  This explains why it was necessary for the POS and ORD
  346. attributes to be defined for integer type variables as mentioned
  347. in an earlier lesson.  Because these attributes are available, the
  348. integer types can be used with this formal generic type.
  349.  
  350.  
  351.  
  352.  
  353.                                                         Page 28-6
  354.  
  355.                                  Chapter 28 - Generic Subprograms
  356.  
  357. THE INTEGER CLASS FORMAL PARAMETER TYPE
  358. _________________________________________________________________
  359.  
  360. The integer formal parameter type, as illustrated in line 16, is
  361. declared with the reserved word type followed by the type name, the
  362. reserved words is and range, and the "box" as illustrated.  The
  363. type name used here can be matched with any actual type that is of
  364. the integer class.  Within the generic subprogram, the arithmetic
  365. operations are available, in addition to all of those operations
  366. available with the discrete generic formal parameter.  But as you
  367. may expect, a generic subprogram using this generic formal
  368. parameter can not be instantiated with an enumerated type.
  369.  
  370.  
  371. THE REAL FORMAL PARAMETER TYPES
  372. _________________________________________________________________
  373.  
  374. The real formal parameter types are declared as illustrated in
  375. lines 7 and 8, with the reserved words digits or delta indicating
  376. the floating or fixed variety of real types.  Only operations
  377. permitted for those types are permitted within the generic
  378. subprogram, and only the respective real types can be used by the
  379. calling program when instantiating a copy of the generic unit.
  380.  
  381. The first procedure simply lists all of the above mentioned generic
  382. formal parameters, but uses none for any purpose.  The second
  383. procedure lists all of the types in a similar manner but declares
  384. a procedure that uses all six for formal parameters as an
  385. illustration.  The program itself uses little of the declared
  386. interface.  Only the type INT_TYPE is exercised in the program
  387. where it is used in a type transformation statement.
  388.  
  389. The details of this program will be left for your study after which
  390. you should compile it.  Because this is composed of only generic
  391. subprograms, it is not executable.
  392.  
  393.  
  394. THE ARRAY TYPE FORMAL GENERIC PARAMETER
  395. _________________________________________________________________
  396.  
  397. Examine the program named ARRAYGEN.ADA for       ================
  398. examples of array type generic formal              ARRAYGEN.ADA
  399. parameters.  The specification and body of a     ================
  400. procedure with a constrained array type generic
  401. formal parameter are given in lines 3 through
  402. 17.  There are actually three generic formal parameters listed
  403. here, one new one on each of the three lines numbered 4 through 6.
  404.  
  405. To define how this procedure is used, we will refer to the
  406. instantiation call in line 49 of this file which happens to be
  407. within the declaration part of the main program.  The generic
  408. formal name SUBSCRIPT must be replaced with an actual parameter
  409. that is of any discrete type because the type mark contains a "<>"
  410. in parentheses.  Furthermore, the first element in the actual
  411.  
  412.                                                         Page 28-7
  413.  
  414.                                  Chapter 28 - Generic Subprograms
  415.  
  416. parameter list will be substituted for this parameter because it
  417. is first in the formal parameter list.  To begin our instantiation
  418. requested in line 49, we can replace every occurrence of the word
  419. SUBSCRIPT in lines 4 through 17 with the word LIMIT_RANGE and we
  420. are on our way to creating a usable procedure.
  421.  
  422. The second parameter of the actual parameter list is the type named
  423. MY_FLOAT, and it will be used to replace every occurrence of the
  424. generic formal type named FLOAT_TYPE listed in the second line of
  425. the generic formal parameters.  You will notice that the required
  426. type is any floating point type because of the occurrence of the
  427. reserved word digits in line 5.  The type of the actual parameter,
  428. as listed in line 50, and defined in line 46 is a floating point
  429. type.  The types therefore match up and the statement in lines 49
  430. and 50 will pass the strong type checking done by the Ada compiler.
  431.  
  432.  
  433. CONSTRAINED ARRAY GENERIC PARAMETER
  434. _________________________________________________________________
  435.  
  436. The third line of the formal parameters, which is line 6, declares
  437. the constrained array with which a given instantiation can be used.
  438. You will notice that this formal parameter depends on both formal
  439. parameters declared previously, but since there is only one new
  440. parameter in this line, the Ada compiler can properly assign the
  441. actual type LITTLE_FLOAT as the replacement for the formal
  442. parameter named CONSTRAINED_ARRAY.  If you actually make a copy of
  443. this generic procedure, and replace the formal parameters with
  444. their corresponding actual parameters, then change the name of the
  445. procedure to Sum_Array, you could replace the instantiation in
  446. lines 49 and 50 with the resulting procedure and the program
  447. operation would be identical.  Of course you would have a problem
  448. of declaring a procedure body prior to some smaller declarations,
  449. but that could be easily fixed.  Lines 64 and 65 give examples of
  450. using the instantiated procedure and will be left to your study.
  451.  
  452.  
  453. UNCONSTRAINED ARRAY GENERIC PARAMETER
  454. _________________________________________________________________
  455.  
  456. Lines 22 through 34 give an example of use of an unconstrained
  457. array as a generic formal parameter, and is nearly identical to the
  458. last example except that the index type is declared to be of type
  459. POSITIVE rather than being flexible as in the last example.  The
  460. type of the index variable could be declared as a generic type
  461. parameter with another line added prior to line 24, and the
  462. instantiating statement would require three types instead of only
  463. two.  Line 60 is the example instantiating statement and lines 67
  464. and 68 give examples of use of the resulting function.
  465.  
  466. As mentioned several times before, each of these subprograms could
  467. be separated into separate files and compiled separately, then used
  468. by any calling program.  Be sure to compile and execute this
  469. program.
  470.  
  471.                                                         Page 28-8
  472.  
  473.                                  Chapter 28 - Generic Subprograms
  474.  
  475.  
  476. THE ACCESS FORMAL GENERIC PARAMETER
  477. _________________________________________________________________
  478.  
  479. Examine the program named ACCESGEN.ADA for our   ================
  480. first look at the last generic formal parameter    ACCESGEN.ADA
  481. type, the access type.  The first procedure, in  ================
  482. lines 2 through 14 use an access type that
  483. matches only an access type which accesses an
  484. INTEGER, resulting in little or no flexibility since an access type
  485. to an INTEGER type variable is used infrequently.  A copy of this
  486. generic procedure is instantiated in line 45 of the main program,
  487. and the procedure is exercised in line 76 as an example for your
  488. study.
  489. The second procedure, given in lines 19 through 32 illustrates a
  490. much more useful procedure because this procedure can be used for
  491. any access type, including the composite types of arrays and
  492. records.  Three copies of the generic procedure are instantiated
  493. in lines 64 through 68 and all three are exercised in the main
  494. program.  Note that the more general procedure is used in line 77
  495. to transpose the INTEGER type variables back to their original
  496. positions.
  497.  
  498. The details of this program should be simple for you to follow, so
  499. no additional comment needs to be made.  Be sure to compile and
  500. execute this program.
  501.  
  502.  
  503. PROGRAMMING EXERCISES
  504. _________________________________________________________________
  505.  
  506. 1.   Add a subtype of INTEGER to SWAPSOME.ADA and determine what
  507.      happens if you instantiate a copy of Exchange_Data for the
  508.      subtype in addition to the instantiation for INTEGER.  Add
  509.      statements to the main program to swap values of the new type.
  510.  
  511. 2.   Attempt to instantiate a copy of Average that uses type FLOAT
  512.      in SWAPSOME.ADA.
  513.  
  514. 3.   Attempt to perform an addition in the body of Exchange_Data
  515.      in violation of the private type.
  516.  
  517.  
  518.  
  519.  
  520.  
  521.  
  522.  
  523.  
  524.  
  525.  
  526.  
  527.  
  528.                                                         Page 28-9