Chapter 6 ARRAYS, TYPES, & CONSTANTS BEGINNING WITH ARRAYS ______________________________________________________________ Examine the program named ARRAYS.MOD and ================ we will go right to our first example of ARRAYS.MOD an array. An array is a list made up of ================ two or more of the same type of element. This construct is usually called a vector by a mathematician, and it is sometimes called a table. Notice the var definition in the sample program and specifically the variable named Automobiles. The reserved word ARRAY followed by the square brackets with a range of numbers contained within them is the proper way to define an array of, in this case, cardinal type variables because of the reserved words OF CARDINAL at the end of the statement. This defines 12 different cardinal type variables, each of which is capable of storing one cardinal number. The names of the twelve variables are given by Automobiles[1], Automobiles[2], ... Automobiles[12]. The variable name is Automobiles and the array subscripts are the numbers 1 through 12. The variables are true cardinal type variables and can be assigned values, or they can be used in calculations or in nearly anyplace in a program where it is legal to use a cardinal type variable. One place they cannot be used is as the index for a for loop since a simple variable type is required there. WHAT GOOD ARE ARRAYS? ______________________________________________________________ Notice lines 10 through 12 of the program. In these lines, each of the 12 variables is assigned a value. When Index is 1, then Automobiles[1] is assigned 11, then when Index is 2, Automobiles[2] is assigned 12, etc. If the 12 variables were defined as 12 separate variables of whatever names we chose for them, we could not assign them values in a loop but would have to assign each one independently. In this instance, we are generating nonsense data but in a real program, this loop could be reading in a series of data from a file such as would be done with a database. The advantage of the array should be very clear, especially if we were to change the array limits to several thousand elements. The statement in line 13 assigns a value to one of the elements at random to illustrate the method. In this particular case, the 7th element of the array named Automobiles is assigned the value of 54. The address of this data is therefore the variable name Automobiles[7] and the 6-1 Chapter 6 - Arrays, Types, and Constants data stored in that address is 54 following execution of line 13. We have therefore assigned values to the 12 variables by a nonsensical but known scheme, and now we can use the 12 variables in any way that is legal within Modula-2. The loop in lines 18 through 24 causes the 12 values to be displayed on the monitor in a neat orderly fashion. In line 20 we display the index of the variable in question, and in line 22, we display the actual variable. Keep in mind that the array subscript could have been of type integer and still be used to display an array of type cardinal provided we defined Index as an integer type variable and always used it as such. Spend enough time with this program so that you thoroughly understand it, then compile and run it. WHAT ABOUT AN ILLEGAL SUBSCRIPT? ______________________________________________________________ Modula-2 does strong type checking and limit checking. If, in the above program, you tried to assign a value to Automobiles[13], which doesn't exist, a run time error would be generated and the program execution would be aborted after giving you an error indication on the monitor. This is one of the advantages of Modula-2 over some of the older programming languages. Some compilers give you the ability to enable or disable this feature. MULTIPLY DIMENSIONED ARRAYS ______________________________________________________________ Examine the file named ARRAYS2.MOD for an =============== example of a program with two-dimensional ARRAYS2.MOD arrays. In this program, the var section =============== contains the variable named Checkerboard which is defined as an 8 element array in which each element is an 8 element array, therefore being an 8 by 8 square array. Each element is capable of storing one cardinal type variable. The variable named Value is defined the same way except that the method of definition is slightly different. The two methods result in the same type and number of variables. In lines 11 through 16 we have two nested for loops. The outer loop causes Index to count from 1 to 8 and for each value of Index, the variable Count counts through the values 1 to 8 also. The net result is that we evaluate the assignments in lines 13 and 14 once for each possible combination of Index and Count. For each combination, we assign some nonsense data to one element of the array variable named Checkerboard then use the result of that calculation to assign some nonsense data to the variable named Value. The purpose here is to illustrate the method of using the double subscripted variables. Next, we display the entire matrix of 6-2 Chapter 6 - Arrays, Types, and Constants Checkerboard in lines 18 through 25. The loops cause 8 values to be displayed on one line so that the entire matrix is displayed on only 8 lines. You should study this logic because you will find output sequences like this to be very valuable. CHANGING A FEW OF THE VALUES ______________________________________________________________ In line 27 and following, we change a few of the values at random for illustrative purposes. Since Value[3,6] is assigned the value of 3, it can be used as one of the subscripts of the next line and in fact it is. This would be a rather sloppy programming style but it is a good illustration of what can be done. Finally using the same technique as that for Checkerboard, the array variable named Value is displayed. HOW MANY SUBSCRIPTS CAN BE USED? ______________________________________________________________ There is no limit as to how many subscripts can be used in Modula-2 by definition, but there is a practical limit of somewhere in the range of 3 or 4. If you use too many, you will very quickly get confused and lose control of what the program is supposed to be doing. I have never seen more than 3 subscripts used in any programming language, and very few instances of more than two. Let the problem definition be your guide. This program was pretty straightforward, and if you understand it, it is time for you to compile and execute it. THE TYPE DECLARATION ______________________________________________________________ Examine the program named TYPES.MOD for a =============== new topic that you will use often, TYPES.MOD especially in large programs. Beginning =============== in line 4, we have a group of type declarations which starts with the reserved word TYPE. The first line defines ArrayDef as a new type that can be used in the same way you would use INTEGER or any of the other simple type definitions. In line 12, the variable named Stuff is defined as a variable of type ArrayDef, and since ArrayDef is a type defining a 14 element array of integer, then Stuff is a 14 element array of integer type variables. It seems like we didn't save anything and in fact we added a few keystrokes to the program in order to do this but there is good reason to define and use a new type. If you look at line 13 you will see that we have also defined Stuff2 as the same type of 6-3 Chapter 6 - Arrays, Types, and Constants array. We have, in fact, defined them to be type compatible which will be very important when we get to the program itself. Continuing down the list of type declarations (once we use the reserved word TYPE, we can define as many types as desired), we define a type with 28 characters, then a type with 60 real variables, and another with 6 boolean variables. The next type definition consists of 12 variables of type DogFood which is itself a type of 6 booleans, resulting in a type consisting of 6 times 12 = 72 boolean type variables. It is possible to continue building up type definitions like this indefinitely, and as you build up applications, you will find yourself building up rather complex type declarations and having a clear picture of how they go together because it is your solution to a problem. The last type to be defined is that named Boat which has exactly the same size and characteristics as type Airplane. We will see shortly that there is a difference in these two definitions. MORE TERMINOLOGY ______________________________________________________________ This is a fine point, but it may help you understand the topic of types better. Lines 4 through 9 are "named types", and line 14 is an "anonymous type". Occasionally in Modula-2, you will find a case where you must have a name for a type and cannot therefore use the anonymous type. Such a case is when you must do a type transformation, or when you are passing data of some type to a procedure. We will make use of this terminology later in this tutorial. HOW DO WE USE ALL OF THIS? ______________________________________________________________ In the var part of the definition part of the program, we declare some variables, two simple types and some of the types we defined above. In the program part, we assign some values to the 72 variables making up the Puppies matrix and the 72 variables making up the Kitties matrix. All of the elements of Stuff are then assigned nonsense values. The really interesting statement comes in line 30 where we say "Stuff2 := Stuff;". In this simple statement, all 14 values stored in Stuff are copied into the 14 corresponding elements of Stuff2 without using a loop. This is possible because the two variables are type compatible, they have the same type definition and the same type name. If you study the definitions above, you will see that Stuff3 is of the same number and range of elements and is composed of the same type of elements as Stuff, namely integer, but they are not type compatible because were not defined with the same type 6-4 Chapter 6 - Arrays, Types, and Constants definition statement. In like manner, even though Puppies and Kitties are identical in type, they are not type compatible. The only operations that can be performed on all of the elements of an array at one time are array assignment, and array parameter passing. You have the ability, through careful assignment of variables, to avoid certain kinds of programming errors. If certain variables should never be assigned to each other, a careful selection of types can prevent it. Suppose for example that you have a program working with peaches and books. You would never want to copy a matrix of peaches to one defining books, it just wouldn't make sense. Those two matrices should be defined with different type declarations even though they may be identical in size. Compile and run this program, even though it will result in no output, then move the comment delimiter in line 31 to a position following the assignment statement and see if it does give you a type incompatibility error. DEFINING A CONSTANT ______________________________________________________________ Examine the program named CONSTANT.MOD for ================ a definition of the constant as used in CONSTANT.MOD Modula-2. We will finally keep the ================ promise made when we studied LOOPDEMO.MOD in chapter 4. The new reserved word CONST is used to define a constant for use in the program. The constant MaxSize can be used anywhere in the program that it is desired to use the number 12, because it is a synonym for the value 12. It can be used as an integer or cardinal number because it is compatible with both types. In fact, it is compatible with the corresponding long types if they are available on your system. Two additional constant values are defined for illustrative purposes only. In the type declaration section we use the constant MaxSize to define two types, then use them to define several variables. In the program there is one for loop using the same constant MaxSize as the upper limit. It doesn't seem to be too useful yet, but suppose your boss came to you and said to change the program so that it handled 142 cases instead of 12. The way the program is written, you would only have to change the value of the constant, recompile, and you would be done. If you had used the number 12 everywhere, you would have to replace every 12 with the new number, 142, being careful not to change the one in line 21 which is a different kind of 12. Of course even that would not be too difficult in such a simple program, but in a program with 5000 lines of code, one simple change could take a week. 6-5 Chapter 6 - Arrays, Types, and Constants Note that a constant must be initialized, but a variable cannot be initialized in Modula-2. Be sure to compile and execute this program. THE OPEN ARRAY IN A PROCEDURE ______________________________________________________________ Examine the program named ARAYPASS.MOD for ================ an example of a program with arrays being ARAYPASS.MOD passed to a procedure. Notice how the ================ procedures are formatted. The rows of asterisks make them really stand out and easy to find. You should begin now to develop your own personal style of formatting in a way that is clear and easy to for you to follow. The two procedures in this program are identical except for the way the arrays are passed to them. In the first procedure named AddNumbers, the formal parameter named Donkey is passed the array from the actual parameter by using the same type which was used to define one of the arrays. The procedure merely adds the values of the elements of the array passed to it and writes the result out to the monitor. The way it is written, it is only capable of adding arrays that are indexed from 10 to 15. Any other array will cause a type incompatibility error. This is simply called passing an array to the procedure. The second procedure named GenAddNumbers has its input array, better known as the formal parameter, defined as an ARRAY OF CARDINAL with no limits stated. This procedure can add all of the variables in any cardinal array regardless of the range of its subscripts. The lower subscript will always be defined as zero within this type of procedure, and the upper limit of the array can be found with the predefined function procedure named HIGH. It is used as shown in the example. The first time this procedure is called in the main program, it is called with the variable SizeOne. In the procedure, the array subscripts for Donkey will be 0 through 5. When the variable named SizeTwo is the array sent to the procedure, then the formal parameter named Donkey will have the limits of 0 and 218. The second procedure definition method is therefore more general. This is called passing an open array to the procedure. WHICH ONE SHOULD I USE? ______________________________________________________________ There will be times when you wish to use the general case for passing a parameter, the open array. A good example is the procedure named WriteString that we have been using in this tutorial. It would be a bit cumbersome if we were only 6-6 Chapter 6 - Arrays, Types, and Constants allowed to pass, for example, a 10 character string to it each time. Since it can accept a string of any length, it is evidently defined with an ARRAY OF CHAR as the formal parameter type in its header. (We will see in a later chapter that this particular procedure is exactly that, a procedure that someone has thoughtfully programmed for you. You only need to tell the system where it can be found using the IMPORT statement.) There will likewise be times when you will desire to use the more specific method of definition. If you are using a lot of arrays and have a specific operation that needs to be done to only a few arrays that have a common definition, you would be wise to use this method. The computer could then tell you if you tried to use the procedure on an array that it was not intended for. This is making wise use of the type checking available in the computer. Note that open arrays are not assignment compatible and are limited to a singly dimensioned array. HANDLING STRINGS IN MODULA-2 ______________________________________________________________ Examine the last example program for this ================ chapter, STRINGEX.MOD, for an example of STRINGEX.MOD using strings in Modula-2. This program ================ is the first program to deviate from the standard library as defined by Niklaus Wirth. When he defined the language, he suggested several library procedures that should be available in every Modula-2 compiler and most compiler writers have followed his suggestions quite closely. He failed to define a standard library for the string handling procedures. There is therefore some freedom for each compiler writer to define the string handling routines in any way he pleases. Most however, have followed at least a resemblance to a standard, so the procedure calls are very similar from compiler to compiler. It may be necessary for you to modify this file to suit your particular compiler. Check your compiler documentation for complete information on how strings are implemented with your compiler. A complete description of the Modula-2 libraries and what they are will be given in chapter 8. BACK TO THE STRINGEX.MOD PROGRAM ______________________________________________________________ The first thing that is different here is the addition of another IMPORT statement in line 10, this one importing procedures from the module named Strings. This is the module containing the procedures which we will need in this program. A string is an array of type char, each element of the array 6-7 Chapter 6 - Arrays, Types, and Constants being capable of storing one character. Thus an array of char type elements is capable of storing a word, a sentence, a paragraph, or even a whole chapter, depending on how big the array is. Using the example given in this program, we will learn how to manipulate text data. One additional feature of the example program will be found on line 24. In this line the WriteString procedure is used in a way we have not seen as yet. Instead of having an expression in quotes, it has the name of a variable within its parentheses. It will display whatever characters are stored in the string named Stuff defined by the ARRAY OF CHAR. So if we learn how to get a string of characters stored in a variable of type string, we can display anything on the monitor that we can generate internal to the computer. According to the definition of Modula-2, a string is an array of char type variables. We will get more familiar with strings as we continue our study. SOME NEW STRING PROCEDURES ______________________________________________________________ The first line of the program itself, line 34, contains a string assignment. In this case, we are telling the system to copy the constant ABCDEFGHIJKL into the variable named Horse. The array into which you are copying must begin at index 0 in order for this to work because all character constants start at zero by definition. The variable Horse, which only contains room for 12 characters will only receive the first 12 characters of the constant. The procedure Display is called with Horse as the actual parameter and the parameter is displayed between parentheses for clarity of understanding, and the 12 characters of the variable are displayed in their ASCII equivalent. When you finally run this program, compare some of the values to the ASCII table that is included with the DOS documentation that came with your computer. In line 37 of the program, the constant 12345 is assigned to the variable named Cow. In the next line, the variable Cow is assigned to the variable Horse, and the display procedure is called again. This time, the variable Cow is shorter than the destination, so the system has to compensate for the difference. After it transfers the 5 characters to Horse, it will place a 0 (zero) in the next position to indicate the end of the string. The definition of the string still has 12 places, but there are only 5 places of interest, so the system will consider all places past the 5th as undefined. This time the system only prints out 5 characters in the procedure. The list of ASCII equivalents shows that the other values are still there, the output routine simply stopped when it came to the zero in the sixth position. 6-8 Chapter 6 - Arrays, Types, and Constants A little refinement of our definition is in order. If a string is full, that means if all character positions are used, a terminating zero is not required. If a string is not full, meaning that less characters are actually used than are defined for the string, a terminating zero is used to indicate the desired length of the string. According to the definition of Modula-2, a char type object is considered to be a string of length 1 and can therefore be handled in any way that it is legal to handle a string. Note that the Assign statement may be different for different compilers because it is not a part of the Modula-2 definition by Niklaus Wirth. CONCATENATION ______________________________________________________________ Concatenation is simply putting two strings together to make up one bigger string. Beginning in line 41, two new string variables are assigned string values, S1 and S2, then the two new variables are concatenated together and assigned to our old favorite variable named Horse. The variable named Horse should now contain the silly expression NeatThings, and when you run the program, you will find that it does. It also has a zero in character position 11, to indicate the end of the string. Line 47 concatenates Horse to Cow and stores the result in Horse, but since the expression is now too long, part of it will get truncated and simply thrown away. Finally, Cow is concatenated to Horse, and the result stored back into Horse. This has the effect of shifting the prior contents of Horse right and adding the characters stored in Cow to the beginning. Line 45 is an example of a string assignment. This is only possible because they are of the same type which means they were defined with the same type name. The variable Cow has a different type so can't be assigned to either of these two variables. Note that the type does not have to start at zero for string assignment to work. Note that even though Horse was the only variable used in the calls to Display, any of the other strings could have been used also. This is the topic of the fourth programming exercise below. Compile and run the program and see if it really does do all that it should do as described above, keeping in mind that you may have to modify the file to accommodate your particular compiler. 6-9 Chapter 6 - Arrays, Types, and Constants PROGRAMMING EXERCISES ______________________________________________________________ 1. Write a program to store the cardinal values 201 to 212 in an array then display them on the monitor. 2. Write a program to store a 10 by 10 array containing the products of the indices, therefore a multiplication table. Display the matrix on the monitor in a neat and readable format. 3. Modify the program in 2 above to include a constant so that by simply changing the constant, the size of the matrix and the range of the table will be changed. 4. Modify the program named STRINGEX.MOD to include calls to Display with each of the string variables at the end of the program. 6-10