



Discriminated Records





	A discriminated record type is a record type that has one or more discriminants.

	In essence, a discriminant is a special field in a record type declaration that typically allows different records of 
that type to differ in terms of size and/or shape.

	For example, a relatively trivial discriminated record type is as follows.



	type Silly_Type (D : Integer) is

		record

			F1 : Integer;

			F2 : Character;

		end record;





	In the above example the descriminant is D, and in this case it is basically just another field in the record with 
some additional restrictions.



Discriminated Records, Cont.



	When a variable of a discriminated type such as Silly_Type is declared, then a value for the discriminant must be 
supplied.



	type Silly_Type (D : Integer) is

		record

			F1 : Integer;

			F2 : Character;

		end record;



	S : Silly_Type (5);

	T : Silly_Type (10);

	U : Silly_Type;								-- Illegal, i.e., does not compile.



	The field D can be referenced just like any other field in the record.  However, it cannot be assigned directly, but 
only via an aggregate.  Furthermore, the discriminant cannot be changed.

	S.F1 := 35;											-- Legal						S.D := 23;						-- Illegal

	S.F2 := `a';											-- Legal						S.D := 5;						-- Illegal

	if (S.D > 0) then											-- Legal

		Integer_Text_IO.Put(S.D);										-- Legal		

	end if;

	S := (5,-8,'z');											-- Legal						S := (52,0,'e');						-- Illegal





Discriminated Records, Cont.





	Typically, a discriminant is used in other field declarations inside the record type.



	type Array_Type is array (Positive range <>) of Integer;



	type List_Type (Max_Size : Positive) is

		record

			List_Count : Natural;

			Elements : Array_Type (1..Max_Size);

		end record;



	Small_List					: List_Type (10);

	Medium_List					: List_Type (100);

	Large_List					: List_Type (1000);





	Note that all three of the above variables are of the same type, and consequently they can be processed by the 
same general-purpose subprogram, such as for performing output.

	Three different types could have been declared, but then each would require a different subprogram.





Discriminated Records, Cont.





	For the discriminated type List_Type, only one output subprogram is required.



	procedure Put (List : in List_Type) is

	begin

		for i in 1..List.List_Count loop

			Integer_Text_IO.Put(List.Elements(i));

			Text_IO.New_Line;

		end loop;

	end Put;





	Put(Small_List);

	Put(Medium_List);

	Put(Large_List);





A Discriminated Record Type

With Multiple Discriminants





	type Array_Type is array (Integer range <>) of Character;



	type A_Type (Col1, Col2, Col3 : Positive) is

		record

			Row1 : Array_Type(1..Col1);

			Row2 : Array_Type(1..Col2);

			Row3 : Array_Type(1..Col3);

		end record;



	A : A_Type(5,3,6);										-- A value for each discriminant must be specified.



	Integer_Text_IO.Put(A.Col1);													-- Legal

	if (A.Col3 > 10) then													-- Legal

		A.Row1(2) := `c';												-- Legal

		A.Row2 := "abc";												-- Legal

	end if;

	A.Col2 := 25;													-- Illegal

	A.Col2 := 3;													-- Illegal

	A := (5,3,6,"abcde","hhh","ijklmn");													-- Legal

	A := (5,5,5,"abcde","fghij","klmno");													-- Illegal





Another Discriminated Record Type

With Multiple Discriminants



	type Matrix_Type is array (Integer range <>, Integer range <>) of Character;



	type B_Type (Len1, Len2 : Positive) is

		record

			Data : Matrix_Type(1..Len1,1..Len2);

			-- Typically, there would be other fields as well.

		end record;



	B : B_Type(4,5);



	Integer_Text_IO.Put(B.Len1);															-- Legal

	if (B.Len2 > 10) then															-- Legal

		B.Data(1,3) := `c';														-- Legal

		B.Data := (others => (`a','b',`c','d',`e'));														-- Legal

	end if;

	B.Len2 := 25;															-- Illegal

	B.Len2 := 5;															-- Illegal

	B := (4,5,(others => (`a','b',`c','d','e')));															-- Legal

	B := (3,5,(others => (`a','b',`c','d','e')));															-- Illegal





Variant Record Types





	A variant record type declaration is a discriminated record type that specifies alternative lists of components.

	type Shape_Type is (Circle, Square, Rectangle);

	type Size_Type is (Small, Medium, Large);

	type Color_Type is (Red, Blue, Green);



	type Figure_Type (Class : Shape_Type) is

		record

			Color : Color_Type;

			Size : Size_Type;

			case Class is

				when Circle =>

					Radius : Float;

				when Square =>

					Side_Length : Float;

				when Rectangle =>

					Height : Float;

					Width : Float;

			end case;

		end record;





Variant Record Declarations and Use



		F1 : Figure_Type (Circle);

		F2 : Figure_Type (Square);

		F3 : Figure_Type (Rectangle);

		F4 : Figure_Type (Circle);

	begin

		F1.Color := Red;

		F1.Size := Small;

		F1.Radius := 3.2;

		F1 := (Circle,Green,Large,6.5);



		F2.Color := Blue;

		F2.Size := Medium;

		F2.Side_Length := 5.25;

		F2 := (Square,Red,Small,10.8);



		F3.Color := Green;

		F3.Size := Large;

		F3.Height := 10.6;

		F3.Width := 2.5;

		F3 := (Rectangle,Blue,Small,3.4,6.5);



		F4 := F1;

	end Main;





Variant Record Declarations and Use





	type Figure_Type (Class : Shape_Type) is

		record

			Color : Color_Type;

			Size : Size_Type;

			case Class is

				when Circle =>

					Radius : Float;

				when Square =>

					Side_Length : Float;

				when Rectangle =>

					Height : Float;

					Width : Float;

			end case;

		end record;





	F1.Class := Square;														-- Illegal

	F1 := (Square,Red,Small,20.0);														-- Illegal

	F1 := F2;														-- Illegal

	F1.Height := 4.5;														-- Illegal

	F1.Width := 5.25;														-- Illegal

	F2.Radius := 65.0;														-- Illegal





Variant Record Use



	package Shape_IO is new Text_IO.Enumeration_IO(Shape_Type);

	package Size_IO is new Text_IO.Enumeration_IO(Size_Type);

	package Color_IO is new Text_IO.Enumeration_IO(Color_Type);



	procedure Put (F : in Figure_Type) is

	begin

		Color_IO.Put(F.Color);

		Text_IO.New_Line;

		Size_IO.Put(F.Size);

		Text_IO.New_Line;

		case F.Class is

			when Circle =>

				Float_Text_IO.Put(F.Radius);

			when Square =>

				Float_Text_IO.Put(F.Side_Length);

			when Rectangle =>

				Float_Text_IO.Put(F.Height);

				Text_IO.New_Line;

				Float_Text_IO.Put(F.Width);

		end case;

		Text_IO.New_Line;

	end Put;
