Record Discriminants and Record Variants
The definition of a record type can have discriminants, which have the same form as formal parameters ("dummy arguments") of subprograms, except that the mode is omitted. Default values may be supplied. For example,
type Matrix is array(Integer range <>, Integer range <>) of Float; type Square_Matrix(Size : Positive := 9) is record Sq : Matrix(1 .. Size, 1 .. Size); end record;
Although objects of type Matrix can be rectangular, objects of type Square_Matrix must be square. In declaring these objects, we use the same syntax as a subprogram call, with either positional or named notation:
A : Square_Matrix(7); -- a 7-by-7 matrix B : Square_Matrix(Size => 5); -- a 5-by-5 matrix C : Square_Matrix; -- a 9-by-9 matrix, using the default -- value of Size
Of course, subtypes of discriminated records can be declared. For example,
subtype Chess_Board is Square_Matrix(Size => 8);
The older Ada 83 RM used a record discriminant in its definition of type Text for the Text_Handler package specification of section 7.6:
Maximum : constant := ... ; subtype Index is Integer range 0 .. Maximum; ... type Text(Maximum_Length : Index) is record Pos : Index := 0; Value : String(1 .. Maximum_Length); end record;
With the simplified version of type Text that we presented earlier, every object of type Text occupied enough memory for the longest string we expected to handle (e.g., 80 characters). With this version, each object of type Text that we create can have just the Maximum_Length we need, and its effective length Pos can vary from zero to that Maximum_Length. For example, we could declare Name : Text(50); and Employee_Number : Text(9).
The definition of a record type can have a variant, which also has the same form as a subprogram formal parameter without the mode. However, the syntax of a case construct is used to specify part of the record. Although a record can have several discriminants, it can have only one variant, and the variant part must appear last in the record. For example,
type Sex_Type is (Male, Female); type Person(Sex : Sex_Type) is record Age : Natural; case Sex is when Male => Bearded : Boolean; when Female => Children : Natural; end case; end record;
If the sex of the person is Male, we want the record to include a Boolean showing whether he's bearded, but if the sex is Female, we want the record to include an Integer (subtype Natural), showing the number of children she has.
Objects are declared and given values as we'd expect:
John : Person(Sex => Male) := (Sex => Male, Age => 21, Bearded => False); Mary : Person(Sex => Female) := (Sex => Female, Age => 18, Children => 0);
Attempting to reference John.Children or Mary.Bearded will raise Constraint_Error. Subtypes may be declared as follows:
subtype Man is Person(Male); subtype Woman is Person(Female);
type Computer_Size is (Handheld, Notebook, Desktop, Mainframe, Cluster); type Computer(Size : Computer_Size) is record MB_Mem : Positive; Disks : Natural; case Size is when Cluster => Number_Of_Units : Positive; Data_Rate : Float; when others => null; end case; end record; My_PC : Computer(Desktop) := (Desktop, MB_Mem => 64, Disks => 2); -- 1 Company_LAN : Computer(Cluster) := (Cluster, MB_Mem => 512, Disks => 8); -- 2Which commented declaration above is illegal?