# Arrays

## Array Variables, Bounds, Aggregates, Range Subtypes

### Simple Array Declaration

• Declare an array variable:
• ```        procedure demo is
squares: array (1 .. 10) of integer;
begin
for i in 1 .. 10 loop
squares(i) := i ** 2;
end loop;
end demo;
```

### Array Bounds are Flexible

• Array bounds can be any integers:
• ```        procedure demo is
squares: array (-10 .. 10) of integer;
begin
for i in -10 .. 10 loop
squares(i) := i**2;
end loop;
end demo;
```
• Later we will see that other types of bounds are possible

### Enumerated Types can be Array Bounds

• Enumerated types (not covered yet) can be array bounds:
• ```        procedure demo is
type days is (Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday);
hours: array(Sunday .. Saturday);

subtype weekdays is days range Monday .. Friday;
work_hours: array(weekdays);
begin
...
end demo;
```
• Later we will see that other types of bounds are possible

### Aggregate Assignment

• An entire array can be assigned in one statement
• ```        procedure demo is
squares: array (1 .. 5) of integer;
begin
squares := (1, 4, 9, 16, 25);  -- aggregate assignment
for i in 1 .. 10 loop
put(squares(i));
end loop;
end demo;
```

• Note that the size of the aggregate must match the declaration

### Aggregate Assignment with Keywords

• Can use indices to specify elements of array in the aggregate value
• ```        procedure demo is
values1: array (1 .. 50) of integer;
values2: array (1 .. 50) of integer;
values3: array (1 .. 50) of integer := (others => 0);
begin
values1 := (2 => 4, 4 => 16, 5 => 25, 3 => 9, others => 0);  -- set remaining to 0
values2 := (others => 0);  -- set all to 0
end demo;
```

### Aggregate: Compared with Java

• Java uses the aggregate:
• only in the declaration
• aggregate defines the size:
• ```            int[] a = {1, 4, 9, 16, 25};
```
• Java has a strange syntax:
• ```        // Does this compile?  How big is the array?
int[] a = {1, 4, 9, 16, 25,}
```

### Subtypes for Array Ranges

• Common to create a subtype for the array range
• ```        procedure demo is
min_int: constant := -10;
max_int: constant := 10;
subtype Int_Range is Natural range min_int .. max_int;

squares: array(int_range) of Natural;
cubes: array(int_range) of Natural;
begin
for i in int_range loop
squares(i) := i**2;
cubes(i) := i * squares(i);
end loop;
end demo;
```

## Array Types, Attributes, and Looping

### Array Types - Anonymous and Named

• squares and cubes each have an anonymous type
• An anonymous type has no name vs a named types
• Arrays with anonymous types are less flexible than with named types
• Can't pass array with anonymous type to a procedure
• Can't compare or assign two arrays with anonymous types

• More common to create a named array type

• Example:
• ```        procedure demo is
subtype int_range is Natural range 1 .. 10;

type IntArray is array(int_range) of Integer;

squares: IntArray;
cubes: IntArray;
begin
for i in int_range loop
squares(i) := i**2;
cubes(i) := i * squares(i);
end loop;
end demo;
```

### Array Attributes

• Attributes of array variables and types:
• 'first
• 'last
• 'range
• 'length

• Attributes let us write code that is independent of the array bounds
• Example:
• ```        procedure demo is
subtype int_range is Natural range 2 .. 5;
type IntArray is array(int_range) of Natural;

squares: IntArray := (4, 9, 16, 25);
begin
put(IntArray'length);

for i in IntArray'first .. IntArray'last loop
put(squares(i));
end loop;

for i in IntArray'range loop
put(squares(i));
end loop;

put(squares'length);

for i in squares'first .. squares'last loop
put(squares(i));
end loop;

for i in reverse squares'range loop
put(squares(i));
end loop;
end demo;
```

### Subtype Attributes

• Subtypes have attributes similar to array attributes:
• 'First, 'Last, 'Range
• But not 'Length, unfortunately
• 'Size is the size in bits, not the length

• Example:
• ```        procedure demo is
subtype Int_Range is Natural range 2 .. 5;
a: array(Int_Range) of natural;
begin
put(Int_Range'size);

for i in Int_Range'first .. Int_Range'last loop
put(i);
end loop;

for i in Int_Range'range loop
put(squares(i));
end loop;

-- Arrays, but not subtypes, have 'length
put(a'length);
-- put(Int_Range'length); -- Compile error
put(a'size);   -- Size in bits

end demo;
```

### Other Ways to Loop Over an Array

• Here are more ways to loop over an array
• ```        procedure demo is
subtype int_range is Natural range 2 .. 5;
type IntArray is array(int_range) of Natural;

squares: IntArray := (4, 9, 16, 25);
begin
-- Use int_range
for i in int_range'first .. int_range'last loop
put(squares(i));
end loop;

for i in int_range'range loop
put(squares(i));
end loop;

-- An iterator
for s OF squares loop
put(s);
end loop;

-- Calculate and output to the fourth paower
-- Use iterator in loop that modifies and printes each array element
for s OF squares loop
s := s * s;
put(s);
end loop;
end demo;
```

### Advantages of Named Array Types

• Easy to make changes to your code

• Makes it possible to:
• Use arrays as procedure parameters
• Assign arrays
• Compare arrays
• Concatenate arrays
• Examples of these operations are below

### Parameters of Array Type

• To pass an array as a parameter, you must use a named array type:
• ```        procedure demoArrayError is

-- Declare a new type
type IntArray is array (1 .. 10) of Natural;

procedure p(a: IntArray) is  -- named type required
begin
put(a(1));
end p;

-- Declare a variable
myArray: IntArray;

begin -- demo
p(myArray);
end demoArrayError;
```
• Error message - This statement:
• ```            procedure p(a: array(1..10) of integer) is
```
• causes this error: anonymous array definition not allowed here

### Array Assignment, Comparison

• We can assign and compare two arrays

• Assignment and comparision on arrays requires the same named type:
• ```        with ada.text_io;
procedure demo is
use bool_io;  -- For printing boolean values

type IntArray is array(1 .. 5) of Natural;

squares: IntArray := (1, 4,  9, 16,  25);
cubes:   IntArray := (1, 8, 27, 64, 125);
begin

put(squares = cube);       --  False
put(squares < cube);       --  False
put(squares <= cube);       --  True

squares := cubes; -- A silly thing to do!

put(squares = cube);       --  True
put(squares < cube);       --  False
put(squares <= cube);       --  True

end demo;
```
• More on assignment and equality is below

## Array Assignment and Equality Test: Reference and Value Types

### Java Array Operations

• What happens with this Java code:
• ```        int[] a = {10, 20, 30};
int[] b = {10, 20, 30};

if (a == b) ...  // T/F ?

b = a;

if (a == b) ... // T/F ?

b[0] = 99;
sop(a[0]);  -- What is printed

if (a == b) ... // T/F ?

```
• What does the memory allocation look like?
• What is a?

### Array Assignment and Equality Tests

• What happens here?
• ```        type Myarray is array (1 .. 3) of Integer;
a, b: Myarray;
...

a := (10, 20, 30);
b := (others => 0);

if a = b then ...  -- T/F ?

b := a;

if a = b then ...  -- T/F ?

b(1) = 99;
sop(a(1));  -- What is printed

if (a = b) ... // T/F ?
```

• Equality test and assignment:
• Equality test and assignment are element by element
• Only allowed if both operands are of the same named type

### Reference and Value Semantics

• For arrays we say that Ada has value semantics
• Java has reference semantics

• Meaning
• Assignment and equality operate on values vs references
• In Ada, an array variable holds an array value, in Java an array variable holds a reference.
• Semantics refers to the meaning of a statement

• Also true for other structured types
• Java objects have reference sementics
• Ada records have value semantics

## Array Flexibility: Declare Blocks and Unconstrained Arrays

### True or False?

• True or False:
• Java arrays are of fixed length: once set they can't be changed

• Ada arrays are of fixed length: once set they can't be changed

• Examples: ...

• But ...

### True or False?

• A Java array is fixed length, but an array reference can point to a different array

• An Ada array is fixed length, but ...
• the array can be allocated at runtime using a declare block
• we can create an Unconstrained Array Type:
• Bounds can be specified at runtime
• Useful for parameters
• Example: type String

### Arrays with Fixed Bounds

• Problem: the array bounds we've seen are fixed at COMPILE TIME and cannot be changed:
• An array variable cannot be redeclared as a different size:
• ```            a: is array(1 .. 10) of integer;
...
a: is array(1 .. 20) of integer; -- ERROR
```
• Procedures only work for given type array
• ```            type ArrayType1 is array(1 .. 10) of integer;
type ArrayType2 is array(1 .. 20) of integer;

procedure putArray(a: ArrayType1) is
begin
...
end putArray;

a1: ArrayType1;
a2: ArrayType2;

begin
putArray(a1);  -- Okay
putArray(a2);  -- ERROR
```

• How can we gain more flexibility:

• Passing the size as a procedure parameter

• Declaring the array in a declare/begin/end block

• With Unconstrained arrays
• Frequently used as parameters (very common)

### Passing Array Size as a Parameter

• Example:
• ```        procedure size_example(N: Natural) is
a: array(1 .. n) of integer
begin
for i in a'range loop
get(a(i));
end loop;
end declare_example;
```
• Useful, but array a does not exist outside the procedure

### Declare Blocks

• Variables can be declared anywhere - with a declare/begin/end block

• Example:
• ```        procedure declare_example is
size: natural;
begin
get(size);

declare
-- Length is fixed at runtime
a: array(1 .. size) of Integer;
begin
for i in a'range loop
get(a(i));
end loop;
-- do whatever you need to do with the array
end;
-- put(a'last); -- Error.  Out of scope

end declare_example;
```
• Scope of a is the declare block

• Most things can be declared in a declare block, even other preocedures (uncommon!)

### Unconstrained Arrays

• Create an array type whose exact bounds are not fixed
• Allows postponing definition of exact bounds of an array
• Frequently used for passing arrays as parameters

• Example (Actual bounds must be a range of Naturals):
• ```            type IntArray is array(Natural range <>) of Integer;

myArray1: Intarray(1 .. 4) := (10, 20, 30, 40);
myArray2: Intarray(1 .. 5) := (10, 20, 30, 40, 50);
```
• Type Intarray is Unconstrained
• Variables myArray1 and myArray2 are Constrained
• Variables must be constrained
• ie, myArray1: Intarray; -- Error
• We will see: Formal Parameters can be Unconstrained!

• Variables of unconstrained types can be compared and assigned:
• Because myArray1 and myArray2 have the same named type
```        procedure tryunc is
type IntArray is array(Natural range <>) of Integer;

myArray1: Intarray(1 .. 4) := (10, 20, 30, 40);
myArray2: Intarray(1 .. 5) := (10, 20, 30, 40, 50);
begin
if myArray1 = myArray2 then   -- True or false?
put_line("same");
else
put_line("diff");
end if;

myArray2 := myArray1; -- Compile warning and RT error
end tryunc;
```

### Unconstrained Arrays as Parameters

• Unconstrained arrays are very useful as parameters
• ```        procedure tryunc is
type IntArray is array(Natural range <>) of Integer;

function sumEmUp(a: IntArray) is
sum: Natural := 0;
begin
for i in a'range loop
sum := sum + a(i);
end loop;
return sum;
end sumEmUp;

myArray1: Intarray(1 .. 4) := (10, 20, 30, 40);
myArray2: Intarray(1 .. 5) := (10, 20, 30, 40, 50);

begin
put(sumEmUp(myArray1));
put(sumEmUp(myArray2));
end tryunc;
```

• Allows declaring parameters that can be arrays of any size
• Attributes are useful (ie necessary!) to get the size

### Declare Blocks and Unconstrained Arrays

• We can combine declare blocks and unconstrained arrays?

• Example:
• ```    with ada.text_io; with ada.integer_text_io;
procedure declare_example2 is

type My_Array_Type is array(Natural range <>) of Integer;

procedure put(a: My_Array_Type) is
begin
for i in A'range loop
put(a(i));
end loop;
end put;

size: natural;
begin
get(size);

declare
a: My_Array_Type(1 .. size);
begin
for i in a'range loop
get(a(i));
end loop;
put(a);
end;
end declare_example2;
```

## Array Concatenation, Strings, and Array Slices

### Concatenation

• & can concatenate any arrays (not just strings) of the same named type
• ```        procedure tryunc is
type IntArray is array(Natural range <>) of Integer;

procedure put(a: IntArray) is
begin
for i in A'range loop
put(a(i));
end loop;
end put;

myArray1: Intarray(1 .. 4) := (10, 20, 30, 40);
myArray2: Intarray(1 .. 5) := (10, 20, 30, 40, 50);

begin
put(myArray1 &  myArray2);
end tryunc;
```

### Strings

• Strings are declared to be unconstrained arrays of characters
• ```        type String is array(Positive range <>) of Character;
```

• Where is String declared?? Package Standard

• Consider this:
• ```        procedure some_strings is
procedure put_reverse(s: String) is
begin
for i in reverse s'range loop
put(s(i));
end loop;
end put_reverse;

s1: String := "To";
s2: String := "Mom";

begin
if s1 = s2 then
put("Same, silly");
else
put_reverse(s1 &  s2);
end if;
end some_strings;
```

### Array Slices

• Any array can be sliced
• Slice = treat a subarray as an entire array!

• Example:
• ```        s: String := "Hi Mom!");
put(s(3 .. 5) & "?");

s(4) := 'T';
put(s);

s(4 .. 6) := "Bob";
put(s);

s(4 .. 4) := "R";
put(s);
```

### Slices as Parameters

• We can pass a slice as a parameter

• Example:
• ```        procedure some_strings2 is
procedure put_reverse(s: String) is
begin
for i in reverse s'range loop
put(s(i));
end loop;
end put_reverse;

begin
put_reverse(s);
put_reverse(s(2 .. s'last-2));
end some_strings2;
```

### Strings are Mutable

• Strings are mutable
• Their values can change
• Obviously, because they are just arrays
• In contrast, Java strings are immutable
• Java Strings are NOT arrays of characters

• Pictures of execution show value semantics

## Multidimensional Arrays

### Multidimensional Array

• Ada has true multidimensional arrays
• It also has arrays of arrays, which is like Java

• Some examples and discussion to come ...