OUR FIRST ARRAY
Example program ------> e_c10_p1.ada
An array is a group of two or more elements that are all of the same type. In Ada, as in most modern computer languages, arrays can be made of many different kinds of data, but all elements of an array must be of the same type. The best way to see this is to inspect the program named e_c10_p1.ada which contains a few examples of arrays.
HOW DO WE DECLARE A SUBSCRIPT?
For simplicity, we will start with line 8 where we have a declaration of the array named Dummy1. This line says that the variable named Dummy1 will have 7 elements numbered from 1 through 7, and each element will have the ability to store one BOOLEAN variable. We will see shortly that the individual elements will be referred to by the variable name followed by a subscript in parentheses, or Dummy1(1), Dummy1(2),... to Dummy1(7). Keep in mind that each is a single BOOLEAN variable.
To define an array, we use the reserved words array and of with the appropriate modifiers as illustrated in this example. We define a range which the array will cover, the type of the range variable, which must be composed of discrete type limits, and the type of each element of the array. Remember that a discrete type is any type of the integer class including enumerated types. We will have an example program with an enumerated array index in part 2 of this tutorial.
LET'S LOOK AT ANOTHER ARRAY DECLARATION
In line 9, we have Dummy2 defined as an array of BOOLEAN type variables that covers the range of Dummy2(-21) through Dummy2(10), since N has the value of 10. Line 10 illustrates declaring the array Dummy3 as an array of BOOLEAN variables from Dummy3(-21) through Dummy3(10), but this time the subscript type is not explicitly stated, only implied by the values of the subscript limits. Actually, the subscript type was not needed in the first two either, since they were implied. The type INTEGER is used so often for an array subscript that the type INTEGER has been defined as the default if none is given. This is done only to make it a little simpler to use arrays.
So far in this program, we have defined about 70 variables that have no initial values because we have not assigned them any. We will see how to initialize an array later, but first we will learn how to use them.
HOW DO WE DEFINE AN ARRAY TYPE?
Line 12 gives the general method of declaring an array type. It uses the reserved word type followed by the type name, the reserved word is, then the definition of the type. The definition is composed of the range, followed by the reserved word of and the element type. We now have a type name which can be used to define any number of array variables, and each will be made up of integer variables. Each will also have 5 elements and will cover the range of 1 through 5. Thus line 14 defines an array of five elements named Total, the elements of which will be named Total(1), Total(2), ... Total(5). Each of these elements can be used to store one value of type INTEGER.
Line 22 of the program illustrates how we can assign a value of 12 to one of the elements of First, which is another array of type MY_ARRAY and therefore composed of 5 elements. The second element is assigned the value of 16, and the third is assigned a value found by subtracting the first element from the second, resulting in a value of 4. This illustrates the use of the elements once they are assigned values. The fourth and fifth elements are also assigned nonsense data, illustrating some mathematical operations. The assignment in line 25 will be explained in the next paragraph. If you remember that each element is an INTEGER type variable, you can use them just like any other INTEGER type variable, except that you must add the subscript to indicate which element you are interested in using at each point in the program.
RENAMING AN ARRAY ELEMENT
Line 19 is an illustration of renaming a single element of the array. Once again, this simply gives us a synonym which we can use to refer to the variable, it does not declare another variable. It should be pointed out that it is not permitted to rename a type but you can achieve the same effect by declaring a subtype with the same range as the parent type.
WHAT IS A RANGE_ERROR?
Any attempt to use a subscript which is outside of the assigned range will result in the system raising the exception Range_Error, and will be handled as a fatal error, terminating operation of the program unless you handle the exception yourself. We will study exceptions in part 2 of this tutorial.
The subscript can be a variable itself, provided it is of the correct type, as is illustrated in line 29, where all five elements of the array named Second are assigned nonsense data for illustration. The subscript can also be calculated, with any arbitrary level of complexity, provided of course that it results in an INTEGER type result and is within the range of the declared subscript.
The assignment in line 32 is legal, provided the two arrays are of the same type, resulting in all 5 values of the array named First being assigned to the five elements of the array named Total. Line 33 illustrates that arrays can even be compared for equality or inequality, and they are considered equal if each element of Total is equal to the corresponding element of First. If there is any inequality, the result is FALSE.
Lines 38 through 45 illustrate a few more of the permissible operations on arrays. You should have no trouble studying them on your own.
WHAT IS AN ANONYMOUS TYPE?
In line 12, we defined a type and gave it a name which we could then use at will throughout the remainder of the program. Any array of this type is said to be of type MY_ARRAY, because it has a name assigned to it. The array declared in line 17 does not have a name associated with it, so it is referred to as an anonymous type.
The array assignment in line 32 was only possible because the two arrays were of the same exact type, and in order to be of the same type, they must be declared with the same type name. The array named Funny has the identical structure as the array First, but it was not declared with the same type name, and it is therefore of a different type and cannot be used in an array assignment statement. Since the array Funny is of an anonymous type, it is impossible to define another array with the same type, so it is impossible to use this array in an assignment statement with any other array.
Line 18 declares the arrays X and Y in the same statement, and it would seem that they should have assignment compatibility, but according to the definition of Ada, the two arrays are of different types because naming both variable names in one statement is merely a shorthand method for naming them in two separate lines. The two arrays are therefore each of a separate anonymous type. This is a fine point, but should be clearly understood.
Two arrays are assignment compatible only if they are declared with the same type name. Compile and run this program and compare the output with the output you expect.
WHAT IS A SLICE OF AN ARRAY?
Example program ------> e_c10_p2.ada
The program named e_c10_p2.ada contains several examples of the use of the slice in Ada, which is a portion of an array. You may wish to assign part of an array to part of another array in a single statement. This can be done with a slice.
We begin by declaring an array type, MY_ARRAY, which is then used to declare two arrays, First and Second. Finally we declare a third array named Funny, which is of an anonymous type, which we explained during our study of the last example program. The current example program will illustrate the difficulty of working with an array of anonymous type, but we will start by working with the named arrays.
WHAT IS A SLICE?
In the executable part of the program, we assign nonsense values to the arrays named Funny and First, so we will have some data to work with. Then in line 22 we tell the system to take elements 3 through 7 of the array named First and assign them to elements 1 through 5 of the array named Second. The term on each side of the assignment operator is a slice, a portion of an array. In order to do the slice assignment as illustrated, both arrays must be of the same type and both slices must have the same number of elements. Of course, all slice limits must be within the declared range limits of the subscripts for the type in use. Line 23 illustrates copying 4 elements from First to Second, and line 24 illustrates copying 6 elements.
In line 25, eight elements are copied from an array to itself in such a manner that the destination and origin portions of the array overlap. Ada is defined such that all of the values are copied in true fashion rather than recopying some earlier copied values again as the copying of values continues. This is because the entire right hand expression is evaluated before the assignment is made to the left side variable. Note that the slice can only be used with a singly dimensioned array.
BACK TO THE ANONYMOUS TYPE VARIABLE
We said that the variable named Funny is an anonymous type and that it would cause some difficulties, so let's see what the problems are. In order to assign all or part of an array to another type of array, we must use a type transformation or get a compile error. Line 27 illustrates how to use a type transformation, as we have seen before. However, we can only do a type transformation based on the entire array, not a portion of it, so we can only transform the type from anonymous to a full sized array of the target type, MY_ARRAY. Therefore we can only copy a slice from the anonymous type variable into the full array of the target. There is no way to transform the type from MY_ARRAY to the anonymous type, since the anonymous type doesn't have a name, so a slice cannot be used to assign to the array variable named Funny. Line 28 illustrates another slice assignment to the complete array named First.
The entire array named First is displayed for your observation. Compile and run this program and examine the output.
A MULTI DIMENSIONAL ARRAY
Example program ------> e_c10_p3.ada
Examine the program named e_c10_p3.ada for our first example of a multidimensional array. We begin by declaring a type named MATRIX which is composed of an array of an array with a total of 12 elements. Each element of the array is referred to by two subscripts following the variable name in parentheses as illustrated in the executable part of the program. Lines 18 through 23 contain a nested loop to fill the variable named Square_Board with a multiplication table, and to fill Chess_Board with all zeros. Note that the variable named Chess_Board is of an anonymous type because there is no type name associated with it.
The entire array named Square_Board is assigned to the array Checker_Board in line 25, which is legal because they are of the same type, which means they were defined with the same type name. Line 27 is used to assign a value of 2 to one element of the Checker_Board, and that value is used in line 28, which states, "Checker_Board(2,4) := 17;", because line 27 assigned the value of 2 to Checker_Board(2,3).
It should be clear to you, based on the discussion of the last program, that even though Chess_Board has the same structure as Square_Board, they are not type compatible and are not assignment compatible. The individual elements are assignment compatible however.
The array named Checker_Board is displayed which you can observe when you compile and run this program. By the way, the array names are poorly chosen in this example because a chess board is not 3 by 4. Good naming conventions help toward developing quality software.
WE NEED SOME FLEXIBILITY
Example program ------> e_c10_p4.ada
The previous program used fixed values for all of the range and loop definitions, which allows very little flexibility, and is therefore considered to be poor programming practice. Of course, it was done for clarity since this was your first look at a multidimensional array. The next program, named e_c10_p4.ada is much more flexible and illustrates some of the slightly more advanced techniques which can be used with Ada.
This program is identical to the last except that there are two constants defined in the declaration part which are then used to define the limits of the arrays and the loops. If you needed to make the program cover a larger range, it would be trivial to modify the constants and recompile the program. Compile and run this program and you will see that it does exactly the same thing as the last one.
WE NEED MORE FLEXIBILITY
Example program ------> e_c10_p5.ada
Examine the program named e_c10_p5.ada and you will find that it is identical to the last two except in the way we define the loop limits. Recall the information we covered on attributes in an earlier lesson and the additions to this program will be simple for you to understand. In line 21 we use the attribute LAST to define the upper limit of the outer loop and add the digit "1" in parentheses to tell the system that we are interested in the first subscript of the array named Square_Board. Line 22 uses a "2" to indicate the LAST value of the second subscript of Square_Board. If no subscript indication is given, the system will default to "1", but it is much clearer for the reader to indicate the "1" in parentheses. It may seem to you to be a lot of trouble to define the limits this way, but when we get to the point where we are writing generalized procedures we will need the flexibility given here. Generic procedures are a long way off too, but these techniques will be absolutely essential when we study them.
Lines 34 and 35 also use attributes for the two loop ranges, but they use the RANGE attribute with the number of the desired subscript in parentheses once again.
When using a singly subscripted array, it is legal to use a "1" in parentheses also, but if none is given, the system will default to one. You should explicitly include the number in a multidimensional array and omit it for a singly dimensioned array as a matter of programming clarity.
HOW DO WE INITIALIZE ARRAYS?
Example program ------> e_c10_p6.ada
Examine the program named e_c10_p6.ada for some examples of array initialization. Seven arrays are declared and the method of aggregate notation, both positional and named, are illustrated. An aggregate is a group of numeric literals, although enumeration values could also be included, that are used in many places in Ada. We will use an aggregate to initialize an array in this example program. The literals can be grouped in the order in which they are used, and this is referred to as a positional aggregate. The literals can also be in a named aggregate, in which the use for each value is defined by using the name of the location to which it should be assigned.
The variable Total is initialized using the positional notation and the variable First is initialized by use of the named notation. Mixed notation is not allowed for array initialization. The array named Another in line 13 contains a new construct using the reserved word others in conjunction with the named aggregate notation. If included, it must be the last entry in the aggregate. The values of Another(1), Another(3), and Another(4) will be initialized to the value of 3. The array named One_More in line 15 illustrates initialization of a range of variables to the value 13, and two variables to the value 27. Note that the others case can be included here but must be last and alone. The other singly dimensioned arrays should pose no problem for you but a few comments are in order concerning the multi dimensional arrays.
Even though you are not permitted to use mixed aggregate notation for an array, the rule is applied at only one level so you can use different methods for each level.
The variable Square_Board uses all positional notation, but Checker_Board uses a named aggregate for the first subscript and positional for the second. Chess_Board mixes things up a little more by using a named aggregate for the first subscript and both methods for the second subscript even though it is consistent within each subgroup and is therefore obeying the rules.
MORE ARRAY EXAMPLES LATER
There is more to be said about arrays, but it will have to wait until we cover a few more topics. This is meant to get you started using arrays, but in a later chapter we will cover additional array topics.
Return to the Table of Contents