An issue arises in the case of variant record objects of whether Size gives information about a particular variant, or the maximum size required for any variant. Consider the following program
with Text_IO; use Text_IO; procedure q is type R1 (A : Boolean := False) is record case A is when True => X : Character; when False => null; end case; end record; V1 : R1 (False); V2 : R1; begin Put_Line (Integer'Image (V1'Size)); Put_Line (Integer'Image (V2'Size)); end q;
Here we are dealing with a variant record, where the True variant requires 16 bits, and the False variant requires 8 bits. In the above example, both V1 and V2 contain the False variant, which is only 8 bits long. However, the result of running the program is:
The reason for the difference here is that the discriminant value of V1 is fixed, and will always be False. It is not possible to assign a True variant value to V1, therefore 8 bits is sufficient. On the other hand, in the case of V2, the initial discriminant value is False (from the default), but it is possible to assign a True variant value to V2, therefore 16 bits must be allocated for V2 in the general case, even fewer bits may be needed at any particular point during the program execution.
As can be seen from the output of this program, the
attribute applied to such an object in GNAT gives the actual allocated
size of the variable, which is the largest size of any of the variants.
The Ada Reference Manual is not completely clear on what choice should
be made here, but the GNAT behavior seems most consistent with the
language in the RM.
In some cases, it may be desirable to obtain the size of the current variant, rather than the size of the largest variant. This can be achieved in GNAT by making use of the fact that in the case of a subprogram parameter, GNAT does indeed return the size of the current variant (because a subprogram has no way of knowing how much space is actually allocated for the actual).
Consider the following modified version of the above program:
with Text_IO; use Text_IO; procedure q is type R1 (A : Boolean := False) is record case A is when True => X : Character; when False => null; end case; end record; V2 : R1; function Size (V : R1) return Integer is begin return V'Size; end Size; begin Put_Line (Integer'Image (V2'Size)); Put_Line (Integer'IMage (Size (V2))); V2 := (True, 'x'); Put_Line (Integer'Image (V2'Size)); Put_Line (Integer'IMage (Size (V2))); end q;
The output from this program is
16 8 16 16
Here we see that while the
'Size attribute always returns
the maximum size, regardless of the current variant value, the
Size function does indeed return the size of the current