Initializing an array of Strings

Ok, most of the troubles with Ada’s String-type comes from a simple misunderstanding of array-types in Ada, namely unconstrained arrays. (I go over it here, explicitly on Strings, but will reiterate; hopefully in a more understandable manner.)

Ok, to start, let us make a few types for illustration:

   Type    Elementary is range 32..64;
   Type    Indexia    is range  0..12;
   Subtype Positivity is Indexia'Succ(Indexia'First)..Indexia'Last;

   Type    Vectoria   is array (Positivity range <>) of Elementary;
   Subtype Fixedia    is Vectoria( 8..11 );

So, here we have Vectoria, an array indexed by Indexia, but which doesn’t have any particular length associated with the type… Fixedia, on the other hand, does have an inherent length: the range of 8 through 11, or a length of 4.

Now, because Vectoria does not have a particular length, we don’t know how much space it takes up, so we cannot say X : Vectoria;… there are two ways to get around this: (a) specifying the index-range in the type-portion of the variable (X : Vectoria(4..7);), or (b) specifying the initial value (X : Vectoria := (33, 48, 60, 55);). — These options are constraining the indefinite nature of the type into something definite.

Once X’s type is definite, it thus has the length associated with it, and this cannot change: so, given that X has a length of 4 in both of those examples, you cannot say either X:= (44, 55, 33); or X:= (64, 54, 44, 34); for the simple reason that the length/indices do not match.

Now, a slight detour, we mention “slices” and “index-sliding” — in the (a) example above the indices are 4..7, but the following is legal X:= Fixedia'(32,42,53,64);, this is because the indices 8..11 of Fixedia are ‘slid’ into the 4..7 that we specified. Indeed, given

Y : Constant Vectoria:= (1 => 64,  2 => 63,  3 => 62,  4 => 61,
                         5 => 60,  6 => 59,  7 => 58,  8 => 57,
                         9 => 56, 10 => 55, 11 => 54, 12 => 53);

we could say X:= Y(X'Range);, which copies the values of the slice on 4..7(61,60,59,58)— into X. Likewise, we could say X:= Y(8..11);, and [IIRC] we could say X:= Y(Fixedia'Range) for 8..11 (because it is length 4), using both slicing and sliding to get the appropriate “window” of our table-of-values.

Now, onto String — but String is not special.
It is simply an array which has elements of a Character-type; which in Ada is specified as any enumeration which has in its definition a character-literal, an element surrounded by single quotes. (See here.) / The only “special” thing about a String type is that you can enclose in double-quotes a sequence of said character-literals. So…

Type Silly_Character is (NUL, BELL, HT, 'A', 'B', DEL);
Type Silly_String    is array(Positive range <>) of Silly_Character;

given the above, you can say K : Silly_String:= "AAAB";, which is shorthand for K : Silly_String:= (1 => 'A', 2 => 'A', 3 => 'A', 4 => 'B'). Now, to use the non-graphic characters, it forces us to use an explicit array-aggregate as in the example, or else use the & operator, so something like J : Silly_String:= BELL & BELL & "BB" & NUL & 'A';.

So, that is why a lot of newcomers to Ada get tripped up on Strings: they forget that they are working with arrays, which are really quite versatile (albeit with some limitations) in Ada because they can be unconstrained.

Hope that helps.

2 Likes