AI22-0051-1

!standard 7.3.3(7/5)                                    23-05-19  AI22-0051-1/04

!standard 10.2.1(5)

!standard 10.2.1(7/5)

!class Binding Interpretation 22-10-26

!status work item 22-10-26

!status received 22-10-26

!priority Medium

!difficulty Medium

!qualifier Omission

!subject Preelaborable_Initialization and contract aspects

!summary

We ignore the four assertion-ish checks that might be performed as part of default initialization (Default_Initial_Condition, Type_Invariant, Static_Prediate, and Dynamic_Predicate) when deciding whether something is preelaborable, and then permit implementations to either omit the checks, or defer them.

!issue

A Default_Initial_Condition (D_I_C) expression is evaluated when a default-initialized object is created. The aspect Preelaborable_Initialization (P_I) does not take into account any such evaluation when it determines whether a component has P_I. That means that such an evaluation could execute operations not otherwise allowed during the elaboration of a preelaborated package (in particular, calling a function other than the handful allowed for preelaboration). This seems to circumvent the purpose of aspect P_I.

!recommendation

(See Summary.)

!wording

Add after 10.2.1(9.1 /5):

For the purposes of the above rules, checks associated with the aspects Default_Initial_Condition, Type_Invariant, Static_Predicate, or Dynamic_Predicate are ignored.

Add after 10.2.1(11.8 /5):

Implementation Permissions

Any checks associated with the aspects Default_Initial_Condition, Type_Invariant, Static_Predicate, or Dynamic_Predicate that would normally accompany the elaboration of a construct that is part of a preelaborated unit, may be omitted completely, or deferred until the beginning of the elaboration of the first library unit that is not preelaborated.

!discussion

This problem occurs in a number of cases, not just Default_Initial_Condition.

(1) The Default_Initial_Condition is evaluated for any default-initialized object of the type associated with the aspect (see 7.3.3(7/5)).

(2) The Type_Invariant is evaluated for any default-initialized object of the type associated with the aspect (see 7.3.2(10/4)).

(3) A Dynamic_Predicate can be evaluated for any default-initialized object of a type with a Default_Value (since the value is converted to the appropriate subtype, and that subtype can have a Dynamic_Predicate, see 3.3.1(11.1/5)). [Note: A Static_Predicate cannot evaluate anything that is not preelaborable.]

(4) A Dynamic_Predicate can be evaluated for any default-initialized object of a type with a Default_Component_Value (since the component value is converted to the appropriate subtype, see 3.3.1(13/5)). Case (3) can also happen for an array object (that also is mentioned in 3.3.1(13/5)).

(5) A Dynamic_Predicate can be evaluated for any component of a default-initialized object if the component has a default expression; again, the component is converted to the appropriate subtype, see 3.3.1(13/5).

None of these cases are covered by the current wording in 10.2.1. It might appear that case (5) is covered by 10.2.1(11.3/2), but it is not; that paragraph talks about the evaluation of the default expression; it does not say anything about the subtype conversion that happens afterward.

—-

Various solutions were considered:

We have adopted a combination of the final two bullets, though we do not require the check to be deferred. It can be omitted, deferred, or performed at the usual time, if that does not interfere with other requirements of preelaboration.

----

Note that the simple solution of not allowing a type that runs afoul of any of these cases to have Preelaborable_Initialization would make it impossible to have a preelaborable package that uses Default_Initial_Condition. A D_I_C is only allowed on a private type, and as such, any useful D_I_C necessarily has to make at least one function call to query the state of the object. So we have adopted the proposal to ignore these assertion-ish checks to determine whether a type has preelaborable initialization, and allow implementations to omit or defer the associated checks.

!example

The Ada.Containers packages illustrate this issue nicely. Following is the specification of the Ada.Containers.Vectors package, showing just the parts relevant to this discussion:

generic
   ...
package Ada.Containers.Vectors
   with Preelaborate, ... is
   type Vector is tagged private
      with ...
           Default_Initial_Condition =>
              Length (Vector) = 0 and then ...,
           Preelaborable_Initialization;

The elaboration of a default-initialized Vector object will finish with the evaluation of the Default_Initial_Condition expression. That will call the function Length. However, that means that such an elaborable construct is not preelaborable by the rules given in 10.2.1(5, 7). Yet we are asserting that this construct is preelaborable by the use of the P_I aspect.

With the new rules, the Vector type can have both preelaborable initialization and a D_I_C aspect. The implementation need not enforce the D_I_C check when it would interfere with preelaboration.

!ACATS test

There should be an ACATS C-Test to verify that D_I_C and other similar aspects are not considered when deciding whether a type can have a Preelaborable_Initialization aspect. There also should be an ACATS C-Test that in a case where an object of such a type is declared other than in a preelaborated package, D_I_C, Type_Invariant, etc. are in fact checked. The ACATS generally does not test Implementation Permissions, and it would be difficult to test the effect of the permission in a preelaborated package anyway, so no test for that case is recommended..

!appendix

This AI was promoted from AI12-0420-1, which was put into the Hold state as it was reported too late to find a solution in time to make the deadline for Ada 2022. This AI is associated with Github Issue #30 (https://github.com/Ada-Rapporteur-Group/User-Community-Input/issues/30).

********************************************************************************