Skip to content

Commit e650b3a

Browse files
authored
Merge pull request #1128 from gusthoff/content/advanced_ada/new_content/arrays/array_derived_types_subtypes/20241020
Adding section on derived array types and array subtypes
2 parents 3d30338 + ef2e1e7 commit e650b3a

File tree

1 file changed

+245
-19
lines changed
  • content/courses/advanced-ada/parts/data_types

1 file changed

+245
-19
lines changed

content/courses/advanced-ada/parts/data_types/arrays.rst

Lines changed: 245 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,33 @@ Arrays
33

44
.. include:: ../../../global.txt
55

6-
Unconstrained Arrays
7-
--------------------
6+
7+
.. _Adv_Ada_Array_Constraints:
8+
9+
Array constraints
10+
-----------------
11+
12+
Array constraints are important in the declaration of an array because they
13+
define the total size of the array. In fact, arrays must always be constrained.
14+
In this section, we start our discussion with unconstrained array types, and
15+
then continue with constrained arrays and arrays types. Finally, we discuss
16+
the differences between unconstrained arrays and vectors.
17+
18+
.. admonition:: In the Ada Reference Manual
19+
20+
- :arm22:`3.6 Array Types <3-6>`
21+
22+
23+
Unconstrained array types
24+
~~~~~~~~~~~~~~~~~~~~~~~~~
825

926
In the
1027
:ref:`Introduction to Ada course <Intro_Ada_Unconstrained_Array_Types>`,
1128
we've seen that we can declare array types whose bounds are not fixed: in that
1229
case, the bounds are provided when creating objects of those types. For
1330
example:
1431

15-
.. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Arrays.Unconstrained_Arrays.Unconstrained_Array_Example
32+
.. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Arrays.Array_Constraints.Unconstrained_Array_Type
1633

1734
package Measurement_Defs is
1835

@@ -40,8 +57,12 @@ In this example, the :ada:`Measurements` array type from the
4057
:ada:`Show_Measurements` procedure, we declare a constrained object (:ada:`M`)
4158
of this type.
4259

60+
61+
Constrained arrays
62+
~~~~~~~~~~~~~~~~~~
63+
4364
The :ref:`Introduction to Ada course <Intro_Ada_Unconstrained_Array_Type_Instance_Bound>`
44-
also highlights the fact that the bounds are fixed once an object is declared:
65+
highlights the fact that the bounds are fixed once an object is declared:
4566

4667
Although different instances of the same unconstrained array type can
4768
have different bounds, a specific instance has the same bounds
@@ -52,21 +73,59 @@ also highlights the fact that the bounds are fixed once an object is declared:
5273
In the :ada:`Show_Measurements` procedure above, once we declare :ada:`M`, its
5374
bounds are fixed for the whole lifetime of :ada:`M`. We cannot *add* another
5475
component to this array. In other words, :ada:`M` will have 10 components for
55-
its whole lifetime.
76+
its whole lifetime:
5677

57-
.. admonition:: In the Ada Reference Manual
78+
.. code-block:: ada
5879
59-
- :arm22:`3.6 Array Types <3-6>`
80+
M : Measurements (1 .. 10);
81+
-- ^^^^^^^
82+
-- Bounds cannot be changed!
83+
84+
85+
.. _Adv_Ada_Constrained_Array_Type:
86+
87+
Constrained array types
88+
~~~~~~~~~~~~~~~~~~~~~~~
89+
90+
Note that we could declare constrained array types. Let's rework the previous
91+
example:
92+
93+
.. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Arrays.Array_Constraints.Constrained_Array_Type
94+
95+
package Measurement_Defs is
96+
97+
type Measurements is
98+
array (1 .. 10) of Float;
99+
-- ^ Bounds are of known and fixed.
100+
101+
end Measurement_Defs;
102+
103+
with Ada.Text_IO; use Ada.Text_IO;
104+
105+
with Measurement_Defs; use Measurement_Defs;
106+
107+
procedure Show_Measurements is
108+
M : Measurements;
109+
-- ^ We cannot change the
110+
-- bounds here!
111+
begin
112+
Put_Line ("First index: " & M'First'Image);
113+
Put_Line ("Last index: " & M'Last'Image);
114+
end Show_Measurements;
115+
116+
In this case, the bounds of the :ada:`Measurements` type are fixed. Now, we
117+
cannot specify the bounds (or change them) in the declaration of the :ada:`M`
118+
array, as they have already been defined in the type declaration.
60119

61120

62121
Unconstrained Arrays vs. Vectors
63-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
122+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
64123

65124
If you need, however, the flexibility of increasing the length of an array, you
66-
could use vectors instead. This is how we could rewrite the previous example
67-
using vectors:
125+
could use the language-defined :ada:`Vector` type instead. This is how we could
126+
rewrite the previous example using vectors:
68127

69-
.. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Arrays.Unconstrained_Arrays.Unconstrained_Array_Example
128+
.. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Arrays.Array_Constraints.Unconstrained_Array_Type_Vs_Vector
70129

71130
with Ada.Containers; use Ada.Containers;
72131
with Ada.Containers.Vectors;
@@ -327,6 +386,7 @@ to highlight the following aspects:
327386
.. admonition:: In the Ada Reference Manual
328387

329388
- :arm22:`3.6 Array Types <3-6>`
389+
- :arm22:`3.6.2 Operations of Array Types <3-6-2>`
330390

331391

332392
Unconstrained Multidimensional Arrays
@@ -525,16 +585,182 @@ we'd like to highlight the following aspects:
525585
form: :ada:`(others => (others => 0.0))`.
526586

527587

528-
..
529-
TO BE DONE:
588+
Derived array types and array subtypes
589+
--------------------------------------
530590

531-
Array Subtypes
532-
--------------
591+
.. _Adv_Ada_Derived_Array_Types:
533592

534-
.. admonition:: In the Ada Reference Manual
593+
Derived array types
594+
~~~~~~~~~~~~~~~~~~~
535595

536-
- :arm:`3.7 Discriminants <3-7>`
596+
As expected, we can derive from array types by declaring a new type. Let's see
597+
a couple of examples based on the :ada:`Measurement_Defs` package from previous
598+
sections:
599+
600+
.. code:: ada compile_button project=Courses.Advanced_Ada.Data_Types.Arrays.Derived_Arrays_And_Subtypes.Derived_Arrays
601+
602+
package Measurement_Defs is
603+
604+
type Measurements is
605+
array (Positive range <>) of Float;
606+
607+
--
608+
-- New array type:
609+
--
610+
type Measurements_Derived is
611+
new Measurements;
612+
613+
--
614+
-- New array type with
615+
-- default component value:
616+
--
617+
type Measurements_Def30 is
618+
new Measurements
619+
with Default_Component_Value => 30.0;
620+
621+
--
622+
-- New array type with constraints:
623+
--
624+
type Measurements_10 is
625+
new Measurements (1 .. 10);
626+
627+
end Measurement_Defs;
628+
629+
In this example, we're deriving :ada:`Measurements_Derived` from the
630+
:ada:`Measurements` type. In the case of the :ada:`Measurements_Def30` type,
631+
we're not only deriving from the :ada:`Measurements` type, but also setting
632+
the :ref:`default component value <Adv_Ada_Default_Component_Value>` to 30.0.
633+
Finally, in the case of the :ada:`Measurements_10`, we're deriving from the
634+
:ada:`Measurements` type and
635+
:ref:`constraining the array type <Adv_Ada_Constrained_Array_Type>` in the
636+
range from 1 to 10.
637+
638+
Let's use these types in a test application:
639+
640+
.. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Arrays.Derived_Arrays_And_Subtypes.Derived_Arrays
641+
642+
with Measurement_Defs; use Measurement_Defs;
643+
644+
procedure Show_Measurements is
645+
M1, M2 : Measurements (1 .. 10)
646+
:= (others => 0.0);
647+
648+
MD : Measurements_Derived (1 .. 10);
649+
MD2 : Measurements_Derived (1 .. 40);
650+
MD10 : Measurements_10;
651+
begin
652+
M1 := M2;
653+
-- ^^^^^^
654+
-- Assignment of arrays of
655+
-- same type.
656+
657+
MD := Measurements_Derived (M1);
658+
-- ^^^^^^^^^^^^^^^^^^^^^^^^^
659+
-- Conversion to derived type for
660+
-- the assignment.
661+
662+
MD10 := Measurements_10 (M1);
663+
-- ^^^^^^^^^^^^^^^^^^^^
664+
-- Conversion to derived type for
665+
-- the assignment.
666+
667+
MD10 := Measurements_10 (MD);
668+
MD10 := Measurements_10 (MD2 (1 .. 10));
669+
end Show_Measurements;
670+
671+
As illustrated by this example, we can assign objects of different array types,
672+
provided that we perform the appropriate type conversions and make sure that
673+
the bounds match.
674+
675+
676+
.. _Adv_Ada_Array_Subtypes:
677+
678+
Array subtypes
679+
~~~~~~~~~~~~~~
680+
681+
Naturally, we can also declare subtypes of array types. For example:
682+
683+
.. code:: ada compile_button project=Courses.Advanced_Ada.Data_Types.Arrays.Derived_Arrays_And_Subtypes.Array_Subtypes
684+
685+
package Measurement_Defs is
686+
687+
type Measurements is
688+
array (Positive range <>) of Float;
689+
690+
--
691+
-- Simple subtype declaration:
692+
--
693+
subtype Measurements_Sub is Measurements;
694+
695+
--
696+
-- Subtype with constraints:
697+
--
698+
subtype Measurements_10 is
699+
Measurements (1 .. 10);
700+
701+
--
702+
-- Subtype with dynamic predicate
703+
-- (array can only have 20 components
704+
-- at most):
705+
--
706+
subtype Measurements_Max_20 is Measurements
707+
with Dynamic_Predicate =>
708+
Measurements_Max_20'Length <= 20;
709+
710+
--
711+
-- Subtype with constraints and
712+
-- dynamic predicate (first element
713+
-- must be 2.0).
714+
--
715+
subtype Measurements_First_Two is
716+
Measurements (1 .. 10)
717+
with Dynamic_Predicate =>
718+
Measurements_First_Two (1) = 2.0;
719+
720+
end Measurement_Defs;
721+
722+
Here, we're declaring subtypes of the :ada:`Measurements` type. For example,
723+
:ada:`Measurements_Sub` is a *simple* subtype of :ada:`Measurements` type. In
724+
the case of the :ada:`Measurements_10` subtype, we're constraining the type to
725+
a range from 1 to 10.
726+
727+
For the :ada:`Measurements_Max_20` subtype, we're specifying |mdash| via a
728+
dynamic predicate |mdash| that arrays of this subtype can only have 20
729+
components at most. Finally, for the :ada:`Measurements_First_Two` subtype,
730+
we're constraining the type to a range from 1 to 10 and requiring that the
731+
first component must have a value of 2.0.
732+
733+
Note that we cannot set the default component value for array subtypes |mdash|
734+
only type declarations are allowed to use that facility.
735+
736+
Let's use these subtypes in a test application:
737+
738+
.. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Arrays.Derived_Arrays_And_Subtypes.Array_Subtypes
739+
:class: ada-run-expect-failure
740+
741+
with Measurement_Defs; use Measurement_Defs;
742+
743+
procedure Show_Measurements is
744+
M1, M2 : Measurements (1 .. 10)
745+
:= (others => 0.0);
746+
MS : Measurements_Sub (1 .. 10);
747+
MD10 : Measurements_10;
748+
M_Max20 : Measurements_Max_20 (1 .. 40);
749+
M_F2 : Measurements_First_Two;
750+
begin
751+
MS := M1;
752+
MD10 := M1;
753+
754+
M_Max20 := (others => 0.0); -- ERROR!
755+
756+
MD10 (1) := 4.0;
757+
M_F2 := MD10; -- ERROR!
758+
end Show_Measurements;
537759

538-
.. todo::
760+
As expected, assignments to objects with different subtypes |mdash| but with
761+
the same parent type |mdash| work fine without conversion. The assignment to
762+
:ada:`M_Max_20` fails because of the predicate failure: the predicate requires
763+
that the length be 20 at most, and it's 40 in this case. Also, the
764+
assignment to :ada:`M_F2` fails because the predicate requires that the first
765+
element must be set to :ada:`2.0`, and :ada:`MD10 (1)` has the value 4.0.
539766

540-
- Complete section!

0 commit comments

Comments
 (0)