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

  1.  
  2.  
  3.  
  4.                                                        Chapter 20
  5.                                            ADVANCED RECORD TOPICS
  6.  
  7.  
  8. A RECORD WITH A DISCRIMINANT
  9. _________________________________________________________________
  10.  
  11. Examine the file named DISCRIM1.ADA for our      ================
  12. first example of a record with a discriminant.     DISCRIM1.ADA
  13. It will take a little time and study before we   ================
  14. get to the discriminant and what it does, but we
  15. will take it a step at a time.
  16.  
  17. We begin by defining an unconstrained two dimensional array type
  18. in line 10 of the declaration part, and an unconstrained one
  19. dimensional array type in line 13.  Next we define a record type,
  20. beginning in line 15, with a discriminant, the discriminant being
  21. a variable named List_Size which is of type POSITIVE.  The record
  22. is composed of four fields, each of which is defined in part by the
  23. discriminant.  The variable named Matrix is a square array whose
  24. size is given by the value of the discriminant, while Elements is
  25. initialized to the square of the discriminant.  Likewise, the other
  26. two fields are defined as a function of the discriminant.  Keep in
  27. mind that the discriminant still does not have a value, it is only
  28. used as a part of the pattern of the record.
  29.  
  30. For later use, we define a derived type in line 23, and a subtype
  31. in line 25.  The subtype is defined as being of type STUFF but with
  32. the discriminant being fixed at 5.  We will have more to say about
  33. these two types later.
  34.  
  35.  
  36.  
  37. WE NEED TO DEFINE SOME DATA NOW
  38. _________________________________________________________________
  39.  
  40. In line 27, we declare a variable named Data_Store to be of type
  41. STUFF with the discriminant set equal to 5.  Therefore, the Matrix
  42. variable which is a part of the record named Data_Store will have
  43. two subscripts, each of which covers a range of 1 through 5.  The
  44. variable named Elements will be initialized to the square of 5, and
  45. the other fields will likewise be defined.  The variable Big_Store
  46. will have larger arrays, and the value of its subfield, named
  47. Elements, will be initialized to a value of the square of 12.
  48. Since these two variables have different numbers of elements, they
  49. are not assignment compatible, nor can they be compared for
  50. equality or inequality.
  51.  
  52. The variable Extra_Store is declared as being of type ANOTHER_STUFF
  53. with a discriminant of 5, but since the types are different, this
  54. variable is not assignment compatible with the first variable named
  55. Data_Store.  More_Store is declared as being of type STUFF with a
  56. discriminant of 5, so it is assignment compatible with Data_Store.
  57.  
  58.                                                         Page 20-1
  59.  
  60.                               Chapter 20 - Advanced Record Topics
  61.  
  62. Five_Store, because it is a subtype of STUFF, and its discriminant
  63. is 5, as defined in the subtype declaration, is assignment
  64. compatible with Data_Store.  Finally, it should be clear that the
  65. last example, Name_Store, is assignment compatible with Data_Store,
  66. since its only difference is that it uses the named method of
  67. discriminant selection.  This is a hint to you that additional
  68. discriminants can be used, and there is actually no limit to the
  69. number that can be a part of a discriminated record type.  We will
  70. have an example program soon that has three discriminants.
  71.  
  72.  
  73.  
  74. WHO IS ASSIGNMENT COMPATIBLE WITH WHO?
  75. _________________________________________________________________
  76.  
  77. As mentioned before, the variables named Data_Store, More_Store,
  78. Five_Store, and Name_Store, are all of the same type and can be
  79. freely assigned to each other.  They can also be compared for
  80. equality or inequality with each other.  The other variables are
  81. of different types and cannot be assigned as a complete record to
  82. each other, or compared for equality or inequality.
  83.  
  84. The discriminant, once declared, is considered to be a constant,
  85. and cannot be modified.  The discriminant of the variable
  86. Data_Store is accessed in the program as Data_Store.List_Size for
  87. purposes of reading it.  The executable part of the program should
  88. be clear.  One of the declared Matrix variables is assigned values
  89. using the RANGE attribute for the loop limits.  The entire record
  90. is then assigned to some additional record variables, and a single
  91. data point is displayed as an example.
  92.  
  93. When you understand the program, compile and execute it to prove
  94. to yourself that it works as shown.  Notice that, as always, the
  95. elements of the record cannot be anonymous types but must be named.
  96.  
  97.  
  98.  
  99. HOW DO WE USE THE NEW RECORDS?
  100. _________________________________________________________________
  101.  
  102. Examine the example program named DISCRIM2.ADA   ================
  103. for a few examples of how to use the               DISCRIM2.ADA
  104. discriminated record.  The type declarations are ================
  105. identical to the last program, but only two
  106. records are declared this time, Data_Store and
  107. Big_Store, which are of different types because they have different
  108. discriminants.
  109.  
  110. The declaration part of the program has a function declaration and
  111. a procedure declaration added to it in this program.  If you look
  112. closely, you will see that the type used for the formal variable
  113. in both subprograms is of the record type STUFF, but there is no
  114. discriminant defined for either.  These are unconstrained records
  115. and add flexibility to the use of subprograms.  The loops within
  116.  
  117.                                                         Page 20-2
  118.  
  119.                               Chapter 20 - Advanced Record Topics
  120.  
  121. the subprograms use limits that are dependent upon the limits of
  122. the actual type as defined in the calling program, and the
  123. subprograms can therefore be used for any record variable of type
  124. STUFF regardless of the value of the discriminant.
  125.  
  126.  
  127.  
  128. USE OF THE UNCONSTRAINED SUBPROGRAMS
  129. _________________________________________________________________
  130.  
  131. The nested loop in lines 48 through 53, assigns the elements
  132. contained in the array variable Data_Store.Matrix to a
  133. multiplication table for later use.  In line 55, we call the
  134. procedure Set_To_Ones with the record Big_Store to set all of its
  135. Matrix values to 1.  Finally, we display the sums of all of the
  136. elements by calling the function Add_Elements once for each record.
  137. Even though the records are actually of different types, the
  138. function works correctly with both, because of the flexibility
  139. built into the function itself.  Note that even though the record
  140. is unconstrained in each subprogram, it is constrained when the
  141. subprogram is called since the discriminant is constrained to the
  142. value of the actual parameter in the call.
  143.  
  144. Be sure to compile and execute this program and study the output
  145. until you are sure you understand the results.
  146.  
  147.  
  148.  
  149. A VARIABLE DISCRIMINANT
  150. _________________________________________________________________
  151.  
  152. Examine the program named DISCRIM3.ADA for an    ================
  153. example of a discriminant that can be changed      DISCRIM3.ADA
  154. dynamically.  This program is nearly identical   ================
  155. to the last example program, but there are two
  156. very small changes.  The discriminant is
  157. initialized to a value of 2 in line 15, which will be used for the
  158. discriminant if none is given in the variable declaration. This is
  159. illustrated in line 25, where the variable Var_Store is declared
  160. to be of type STUFF, and is defaulted to the initialization value
  161. of 2 for its discriminant.  There is one other property that it has
  162. acquired, and that is the ability to have its discriminant changed
  163. to any legal value during execution of the program.
  164.  
  165. The two variables named Data_Store and Big_Store have their
  166. discriminants fixed at 5 and 12 respectively and cannot be changed
  167. during program execution.
  168.  
  169.  
  170. HOW DO WE CHANGE THE DISCRIMINANT?
  171. _________________________________________________________________
  172.  
  173. The discriminant can only be changed by changing the entire record
  174. in a single statement as is illustrated in line 56 where the entire
  175.  
  176.                                                         Page 20-3
  177.  
  178.                               Chapter 20 - Advanced Record Topics
  179.  
  180. record named Data_Store, with a discriminant of 5, is assigned to
  181. the variable Var_Store.  The variable Var_Store can then be used
  182. anywhere it is legal to use a record of discriminant 5 as shown in
  183. lines 57 through 63.  Note that prior to the assignment in line 56
  184. the variable Var_Store can be used as a record with its
  185. discriminant set to 2 as the default.
  186.  
  187. In line 67, the variable Var_Store is assigned the entire record
  188. of Big_Store which effectively changes it into a record variable
  189. with a discriminant of 12.  The fact that it is changed is
  190. evidenced by the output which you can see after you compile and
  191. execute this program.  Note that all of the values contained in
  192. Big_Store are copied into Var_Store.  Be sure to compile and
  193. execute this program.
  194.  
  195.  
  196.  
  197. A MULTIPLE DISCRIMINANT
  198. _________________________________________________________________
  199.  
  200. Examining the example program named DISCRIM4.ADA ================
  201. gives you an example of how to use a multiple      DISCRIM4.ADA
  202. discriminant in a record type.  The first        ================
  203. difference is in lines 15 through 17 where three
  204. discriminants are defined for the record type,
  205. and the next big difference is in lines 25 through 31 where 5
  206. variables are declared with this type illustrating the various
  207. kinds of discriminant initialization described in this chapter.
  208.  
  209. Since we have studied all of these in the last few example
  210. programs, we will not elaborate on them, except to mention that the
  211. variable named Variable can be assigned the value of any of the
  212. other variables.  It will then have the entire set of discriminants
  213. assigned to it that the assignment variable possesses and it will
  214. be assigned all of the current values stored in the source record.
  215. This is exactly the same as what was illustrated in the last
  216. program.
  217.  
  218. Be sure to compile and run this program after you understand the
  219. concepts it is meant to convey to you.
  220.  
  221.  
  222.  
  223. A VARIANT RECORD
  224. _________________________________________________________________
  225.  
  226. Examine the file named VARIANT1.ADA for our      ================
  227. first example of a variant record.  A variant      VARIANT1.ADA
  228. record must have a discriminant, by definition,  ================
  229. since the discriminant will define which of the
  230. various variants each record variable will be
  231. composed of.  If you are a Pascal programmer you will find the
  232. variant record to be much more confining than in Pascal where you
  233. can change the variant at will.  If you remember that Ada is a very
  234.  
  235.                                                         Page 20-4
  236.  
  237.                               Chapter 20 - Advanced Record Topics
  238.  
  239. strongly typed language, and will accept no deviation from its
  240. defined standard in order to detect errors inadvertently introduced
  241. by the programmer, you will appreciate the terse definition and
  242. restrictions.
  243.  
  244. The discriminant for our example record is declared in line 10 as
  245. an enumerated type with four allowable values.  A variable named
  246. Engine is declared, which is of type POWER, which will be used as
  247. the discriminant and two variables are declared as the first part
  248. of the record.  The variant part of the record begins in line 16
  249. with the reserved word case followed by the name of the
  250. discriminant variable, which is Engine in this example.  The four
  251. variants are declared in much the same way as a normal case
  252. statement with variable declarations in place of the executable
  253. statements.  There must be a clause listed for each possible value
  254. of the discriminant, and any number of variables may be defined for
  255. each, including none.  If no variables are declared for a case, the
  256. reserved word null is used to indicate to the compiler that you
  257. really mean to include no variables there.
  258.  
  259. If there is a variant to the record, it must be the last part of
  260. the record with all common variables declared first.  One or more
  261. of the variant parts of the record can have a variant part itself,
  262. provided it is the last part of the variant part.  There is no
  263. defined limit to the nesting.
  264.  
  265.  
  266.  
  267. HOW DO WE USE THE VARIANT RECORD?
  268. _________________________________________________________________
  269.  
  270. In line 25, we declare the variable Ford to be a record of type
  271. VEHICLE, and constrain it to be the GAS variant of the record.
  272. Because the Ford variable is constrained to the GAS variant, it can
  273. only use the variable declared as part of the GAS variant, and of
  274. course the two common variables.  It would be illegal to assign
  275. data to the fields of the Ford variable which are declared in the
  276. other variants of the record type.  Moreover, since the variable
  277. Ford has been assigned the discriminant value of GAS, it can never
  278. be changed, but is a constant.  Likewise, the variable named Truck
  279. will always be a record of type VEHICLE with the variant DIESEL
  280. because that is what it is declared with.  The same is true of the
  281. other two variables declared in lines 27 and 28.  We will see in
  282. the next program, that it is possible to declare a variable in such
  283. a way that it can be modified dynamically to any of the variants
  284. as the program is executing.
  285.  
  286.  
  287.  
  288. HOW DO WE ASSIGN VALUES TO THE VARIABLES?
  289. _________________________________________________________________
  290.  
  291. Lines 32 through 34 should be familiar to you since this is the
  292. method used to assign values to a record with no variant, which we
  293.  
  294.                                                         Page 20-5
  295.  
  296.                               Chapter 20 - Advanced Record Topics
  297.  
  298. studied earlier.  Line 36 illustrates value assignment by using a
  299. positional aggregate notation, and line 39 illustrates assignment
  300. of values using the named aggregate notation.  In both of these
  301. cases, all four fields must be named even if some are not changed.
  302. Even the invariant discriminant must be included in the aggregate,
  303. which seems to be somewhat of a nuisance, since it is a constant.
  304. The reasons for these last two rules are probably well founded and
  305. have to do with ease of writing a compiler, which is certainly no
  306. small job.
  307.  
  308. The statements in lines 42 through 45 assign values to each of the
  309. subfields of the record variable named Stanley, and the mixed
  310. aggregate assignment is illustrated in line 47, where all five
  311. variables are mentioned even though the discriminant is a constant.
  312. Finally, the Schwinn and Truck variables are assigned values in
  313. lines 50 through 56.  Compile and execute this program to assure
  314. yourself that your compiler will indeed compile it correctly.
  315.  
  316.  
  317.  
  318. A VARIABLE VARIANT RECORD
  319. _________________________________________________________________
  320.  
  321. Examine the program named VARIANT2.ADA for an    ================
  322. example of a variant record in which we can        VARIANT2.ADA
  323. change the variant dynamically during program    ================
  324. execution.  A major difference here is that the
  325. discriminant is defaulted to the value listed in
  326. line 12, namely the value of NONE.  If no variant is declared, it
  327. is defaulted to NONE in the declarations as is done in line 25,
  328. where three variable records are declared using the default value
  329. of the discriminant.  The variable Stanley is once again declared
  330. to be of the variant STEAM, and this will remain constant
  331. throughout the execution of the program, because any variable
  332. declared with a discriminant value cannot have the value of its
  333. discriminant changed dynamically but is a constant, although the
  334. individual elements of the record can be changed.
  335.  
  336.  
  337.  
  338. NOW TO USE SOME OF THE NEW VARIABLES
  339. _________________________________________________________________
  340.  
  341. In line 30, the variable Ford is assigned data such that it is of
  342. the GAS variant, using the positional aggregate notation, and is
  343. redefined in the next statement to be of the DIESEL variant, by
  344. using the mixed aggregate notation.  This is done to illustrate to
  345. you that it is possible to change the variant of a variable if it
  346. was declared with the default variant.  In line 33, the variable
  347. Truck is assigned the DIESEL variant with the positional aggregate
  348. notation, and two of the fields are changed in the next two
  349. statements.
  350.  
  351.  
  352.  
  353.                                                         Page 20-6
  354.  
  355.                               Chapter 20 - Advanced Record Topics
  356.  
  357. Any of the fields can be changed individually with the exception
  358. of the discriminant variable, which can only be changed by use of
  359. an aggregate in which all values are listed.  Remember that this
  360. is the aggravating part of this construct, that all of the fields
  361. must be mentioned in every record aggregate.  Even though you can
  362. change individual values of the record, you are limited to using
  363. those variables that are part of the current variant.  Pascal
  364. allows you to use variable names of other variants but Ada will not
  365. permit this.  You are permitted to use the positional, named, or
  366. mixed aggregate notation, however.  Be sure to compile and execute
  367. this program after you understand the concepts.
  368.  
  369.  
  370.  
  371. OPERATOR OVERLOADING
  372. _________________________________________________________________
  373.  
  374. The example program named INFIX.ADA could be      ===============
  375. placed in several different places in this           INFIX.ADA
  376. tutorial, because it doesn't really fit anywhere  ===============
  377. too well.  Since one of the most advantageous
  378. places to use operator overloading is with
  379. record type variables, this seemed like a good place for it.  The
  380. program itself is very simple, but the concept is potentially very
  381. powerful.
  382.  
  383. We first define a record composed of three simple variables all
  384. being of type INTEGER, and use this definition to declare three
  385. variables of this type.  The next declaration is of a function
  386. named "+", which we can define to do anything we wish it to do.
  387. In this case we input two variables of the record type THREE_INTS
  388. and return one record of the same type.  Within the function, we
  389. add all three fields of one variable to the corresponding fields
  390. of the other variable, and return the record consisting of the sum
  391. of the two input records.  To make it even more convenient, Ada
  392. allows you to use the overloaded operator in an infix notation as
  393. illustrated in line number 33 of the program where two records are
  394. added together and assigned to the record variable named Sum.  This
  395. line is actually a call to the function we defined earlier and
  396. named "+".
  397.  
  398. It could be a bit confusing if you consider the addition in line
  399. 27 where the usual addition operator is used.  Ada will decide
  400. which + operator to use based on the type of the constants or
  401. variables to be added together.  If you were to try to use this
  402. operator on a record of some other type, such as the VEHICLE record
  403. from the last program, the system would generate a type error
  404. during compilation.  As mentioned previously, it is only possible
  405. to overload existing operators.  You cannot define a new operator,
  406. such as &=, and use it for some operation.
  407.  
  408. Recall the chapter named Advanced Array Topics where we overloaded
  409. the "+" operator in the example program named ARRAYOP2.ADA.  Both
  410. overloadings of this operator could be included in a single program
  411.  
  412.                                                         Page 20-7
  413.  
  414.                               Chapter 20 - Advanced Record Topics
  415.  
  416. and the system would be able to find the correct overloading for
  417. each use by checking the types used.  Be sure to compile and
  418. execute this program even though it has no output.
  419.  
  420.  
  421.  
  422. PROGRAMMING EXERCISES
  423. _________________________________________________________________
  424.  
  425. 1.   Add some output statements to VARIANT1.ADA to display some of
  426.      the results.
  427.  
  428. 2.   Try to change the variant of Stanley in the same way we
  429.      changed the variant of Ford in the example program named
  430.      VARIANT2.ADA to see what kind of error messages you get.
  431.  
  432. 3.   Add another overloading function to INFIX.ADA which uses the
  433.      "+" operator to add all six elements of two records together
  434.      and return a single INTEGER type variable.  The system can
  435.      tell which overloading you wish to use by the return type
  436.      associated with the function call.
  437.  
  438.  
  439.  
  440.  
  441.  
  442.  
  443.  
  444.  
  445.  
  446.  
  447.  
  448.  
  449.  
  450.  
  451.  
  452.  
  453.  
  454.  
  455.  
  456.  
  457.  
  458.  
  459.  
  460.  
  461.  
  462.  
  463.  
  464.  
  465.  
  466.  
  467.  
  468.  
  469.                                                         Page 20-8