Pages

Tuesday, August 21, 2012

AdaTutor - Records and Arrays (2)

Multidimensional Arrays

Ada arrays may have any number of dimensions, and the subscripts may be of
different discrete types.&nsp; For example, assuming Rainbow_Color, Month_Type, and
Date have already been defined, we can write

Here the first subscript is of type Integer and has 10 possible values, the
second subscript is of type Rainbow_Color and has four possible values, and the
third subscript has type Month_Type with five possible values. Thus we have
a three-dimensional array of 10 * 4 * 5 = 200 Dates. One element of the array
might be X(-5, Green, Apr); one field of that element might be
X(-5, Green, Apr).Year. The array in this example probably has no use, other
than demonstrating that multiple subscripts need not have the same type.

If one subscript of a multidimensional array type is constrained, they must all
be constrained. We can't write

We initialize or assign an array of arrays with nested aggregates, the same as
a multidimensional array. However, we reference a single element differently:

type Square10 is array(1..10,1..10)ofInteger;type Row10 is array(1..10)ofInteger;type Mat10 is array(1..10)of Row10;-- S is a two-dimensional array.
S : Square10 := (others=> (others=>0));-- M is an array of arrays.
M : Mat10 := (others=> (others=>0));...
S(4,5) :=1;-- a single element of a two-dimensional array
M(4)(5) :=1;-- a single element of an array of arrays

The "short circuit" forms can prevent us from using array subscripts that are
out of range. For example, if we write

A :array(1..10)ofFloat;
I :Integer;...if I in A'Rangeand then A(I) =0.0then-----;-----; (block of code)-----;end if;

then we know the program won't try to evaluate A(I) when I is outside the range
1 to 10.

No, the above is legal. The elements of an array can be of any type, including
other arrays. Here Pg has type Page, which is an array of List. Therefore
Pg(5) has type List (which is an array of Integer), and Pg(5)(10) has type
Integer. Thus the assignment is legal. The notation Pg(5)(10) may seem
strange, but it's correct Ada when we have an array of arrays.

You're right! The above is illegal because the range of the subscript must be
specified, either in the first line, (Integer range 1 .. 10), or in the
second, R1 : Row(1 .. 10);, but not both. This is the unconstrained array
error mentioned earlier.

Strings

There's a very important array type declaration built into the Ada language.
As with types Boolean and Character, and subtypes Positive and Natural, this
definition comes with Ada and shouldn't be repeated in our programs:

typeStringis array(Positiverange<>)ofCharacter;

(In Ada 95, type Wide_String is similarly defined as an array of
Wide_Character.) Thus we can declare, for example, S : String(1 .. 5);. We
can't simply write S : String; because we can't declare unconstrained array
objects. (We can declare S : constant String := "Hello"; and in Ada 95, we may
write S : String := "Hello"; because the compiler will translate this to
S : String(1 .. 5) := "Hello";). Note that String isn't a special type in Ada;
it's just an array of Characters. Everything we learned about arrays applies
to Strings. For example, we can assign to S using the same syntax that we use
when assigning to an array of any other type. If we write
S : String(1 .. 5); we can write:

S := ('H','e','l','l','o');

However, this notation is clumsy, so Ada allows us to abbreviate an array of
Character constants using double quotes. Thus S := "Hello"; is equivalent to
the statement above. If a quotation mark appears inside the string, it must be
doubled. Thus Ada.Text_IO.Put_Line("a ""big"" man"); will display a "big" man.

It may seem disappointing that Ada Strings have fixed length, and that we can't
declare a variable S : String;. Fortunately, Ada 95 comes with several
string-handling packages to simulate variable-length strings; see
Annex A of
the Ada 95 RM. The name of the Ada 95 package that provides "Unbounded-Length
String Handling" is Ada.Strings.Unbounded, described in
Annex A.4.5 of the Ada 95 RM.

Also, later we'll learn how to define our own type Text to get around this
restriction and simulate variable-length Strings even in Ada 83.

When arrays are assigned, the lengths must be the same on both sides of the :=,
and the types must be the same, but the subscripts needn't be the same.
For example, if we have

then we can write V1 := V2; and S1 := S2; even though the subscripts are
different, because the array lengths are the same and the element types are the
same. But we'll get a Constraint_Error if we write S1 := "Hello there"; or
S1 := "Hi"; or V1 := (1.0, 2.0, 3.0);, because these arrays have wrong lengths.
Ada won't automatically truncate Strings or pad with blanks. Of course, it
would be easy to write our own procedure to assign Strings of different
lengths, padding or truncating as necessary.

A slice of an array is a portion of an array, and is indicated with a range in
the subscript. A slice is itself an array. Some languages use the term
"substring" to refer to a slice of a String, but in Ada we can take a slice of
any kind of array, not just an array of Characters. So instead of "substring,"
Ada uses the more general term "slice." For example, if we have

A :array(1..10)ofInteger:= (1,2,3,4,5,6,7,8,9,10);

then A(1 .. 3) is the array (1, 2, 3) and A(6 .. 9) is the array (6, 7, 8, 9).
Similarly, if we have S : String(1 .. 11) := "Hello there"; then S(8 .. 11) is
"here" and S(4 .. 5) is "lo". We can also write S(1 .. 10) := S(2 .. 11); and
A(1 .. 3) := A(4 .. 6); since the lengths are the same on both sides.

If the value preceding .. is greater than the value following it, we have a
null range. A slice with a null range has a length of zero, and is called a
null slice. In the case of a null slice, the subscript is not checked for
Constraint_Error. Thus, even if N is 0 we could write S(1 .. N); which would
produce the null string "". This is legal, even though Ada defines
"type String is array(Positive range <>) of Character;". Assigning a null
slice to a null slice does no harm and generates no error; it does nothing.
Also, if S is a null array, then S'Length is 0, and S'First and S'Last don't
exist. Using 'First or 'Last with a null array will raise a Constraint_Error.

Beginners sometimes confuse a Character with a String of length 1. If we
write

S :String(1..10);
I :Integer:=5;

then S(I) is a Character and S(I .. I) is a String of length 1. Also, 'X' is a
Character while "X" is a String of length 1. Thus we could write

S(I) :='X';
S(I .. I) :="X";

but we'd be mixing types if we were to write S(I) := "X"; or S(I .. I) := 'X';.

Fortunately, Ada.Text_IO has a Put for type Character as well as a Put for type
String. (It also has a Get for each of these types.) Thus we can write either
Put(S(I .. I)); or Put(S(I));. However, Put_Line and Get_Line exist only for
Strings, not for Characters. We'll learn about Ada.Text_IO in more detail
later.

You're right! Number 4 creates Hello, a String of length 5, and initializes it
to "Hello", a String of the same length. The subscript of Hello need not start
at 1, so long as the length is 5.

Number 1 attempts to create an unconstrained array. Number 2 has a zero
subscript, while Ada defines type String for Positive subscripts. Number 3
should have '*' instead of "*". Number 5 tries to set each of the first
three elements, which are Characters, to a String. Number 6 tries to store a
String of length 1 into a String of length 3, and number 7 should have "Hello"
instead of 'Hello'.

No, number 5 is illegal because it tries to initialize each of the first three
elements, which are Characters, to a String of length 3. We could, however,
have written simply Hello : String(1 .. 5);, and then written the following in
the executable region:

No, number 7 is illegal because it should say "Hello" instead of 'Hello'. Ada
"tic" marks (') always enclose a single Character, while double quotes (")
always enclose an array of Characters.

Which one of the above is legal?

Array Operators

The operator & concatenates any two arrays of the same type, including two
Strings. It can also concatenate a single element with an array of that
element type, or two single elements into an array of length two. For example,
every use of & below is legal:

The operators and, or, xor, and not, defined for Booleans, are also defined for
one-dimensional arrays of Boolean. They operate element by element on the
arrays. Thus, we can simulate sets in Ada. For example, if we write

The operators = and /= can compare two records or two arrays of the same type.
Records are equal if all of their corresponding fields are equal, arrays, if
all of their corresponding elements are equal. Arrays of different lengths
are always unequal. The four remaining relational operators can compare two
arrays of the same type. They're compared element by element until a
difference is found. For example, if we have