Version 1.1 of ai05s/ai05-0130-1.txt

Unformatted version of ai05s/ai05-0130-1.txt version 1.1
Other versions for file ai05s/ai05-0130-1.txt

!standard 7.6(12)          08-12-04 AI05-0130-1/01
!standard 7.6.1(9/2)
!class binding interpretation 08-12-04
!status work item 08-12-04
!status received 08-10-17
!priority Low
!difficulty Medium
!qualifier Error
!subject Order of initialization/finalization of record extension components
!summary
!question
When a record contains two fields, one with an access discriminant and one without, the field with the access discriminant is initialized last and finalized first.
Does this also apply for record extensions? It would seem that the wording in 7.6(12) means that some of the components of a parent type could be required to be initialized after the extension components. In the worst case, it could make composition of initialization/finalization operations impossible (the operations would have to be different for every extension in order to get the ordering right).
Is this the intent?
!recommendation
(See Summary.)
!wording
!discussion
The question is asking about an example like:
with Ada.Finalization; package Pak1 is type Rec0;
type Rec1 (D : access Rec0) is new Ada.Finalization.Limited_Controlled with null record;
type Rec0 is tagged limited record Comp1 : Rec1 (Rec0'access); -- has access discriminant end record;
type Rec2 is new Ada.Finalization.Limited_Controlled with null record;
procedure Initialize (X : in out Rec1); procedure Finalize (X : in out Rec1);
procedure Initialize (X : in out Rec2); procedure Finalize (X : in out Rec2);
type Rec4 is new Rec0 with record Comp2 : Rec2; -- no access discriminant end record;
end Pak1;
with Ada.Text_IO; package body Pak1 is
procedure Initialize (X : in out Rec1) is begin Ada.Text_IO.Put_Line ("Initialize Rec1"); end Initialize;
procedure Finalize (X : in out Rec1) is begin Ada.Text_IO.Put_Line ("Finalize Rec1"); end Finalize;
procedure Initialize (X : in out Rec2) is begin Ada.Text_IO.Put_Line ("Initialize Rec2"); end Initialize;
procedure Finalize (X : in out Rec2) is begin Ada.Text_IO.Put_Line ("Finalize Rec2"); end Finalize;
end Pak1;
with Pak1; procedure Test1 is X : Pak1.Rec4; begin null; end Test1;
The language rules as currently constituted require that this program print:
Initialize Rec2 Initialize Rec1 Finalize Rec1 Finalize Rec2
But the reason for this requirement is in order that the Initialize operation for a component with a self-referential access discriminant can assume that other components of the enclosing object have already been properly initialized (AARM 7.6(12.b)). Such a component cannot access (or even know about) components of any extensions, so there does not appear to be any value to having this requirement apply to all of the components of a type extension (rather than just to the extension components alone).
This requirement surely increases the burden of understanding initialization of a type extension, as it is not simply composing the initialization of the parent part with the extension components.
Moreover, there is potentially an extra implementation cost here. If the implementation uses a subprogram to initialize components of a tagged type T, it would make sense to use that subprogram to initialize the parent components of an extension of T (and just initialize the extension components directly in T). But that would be complicated by this requirement, and could not be done at all in unusual cases.
[Not sure what the right answer is here. Changing the rule could cause a subtle incompatibility in existing programs, and not changing the rule also could cause such an incompatibility (one presumes that this AI will spawn an appropriate ACATS test, whatever the decision is), by causing implementers to change their implementations to match the actual wording rather than their understanding.]
--!corrigendum 7.6.1(9/2)
!ACATS Test
An ACATS test should be constructed to test a case like the example given here, in order to verify that the rule is implemented properly.
!appendix

!topic  order of initialization/finalization of record components
!reference Ada 2005 RM 7.6(12), RM 7.6.1(9), AARM 7.6(12.b), AARM 7.6(9.a)
!from Dan Eilers 2005-10-17
!keywords initialize finalize access discriminant
!discussion

When a record contains two fields, one with an access discriminant and one
without, the field with the access discriminant is initialized last and
finalized first. The AARM explains:

  7.6(12.b):

   The fact that Initialize is done for components with access
   discriminants after other components allows the Initialize operation
   for a component with a self-referential access discriminant to assume
   that other components of the enclosing object have already been
   properly initialized.

  7.6.1(9.a):

   Reason: This allows the finalization of a component with an access
   discriminant to refer to other components of the enclosing object
   prior to their being finalized.

Is this rule supposed to apply even when the record is a type extension, and
the field with the access discriminant is in the ancestor part of the record?
The fields in the ancestor part should probably be initialized first and
finalized last, right?

    with Ada.Finalization;
    package Pak1 is
        type Rec0;

        type Rec1 (D : access Rec0) is new
            Ada.Finalization.Limited_Controlled with null record;

        type Rec0 is tagged limited record
            Comp1 : Rec1 (Rec0'access);     -- has access discriminant
        end record;

        type Rec2 is new Ada.Finalization.Limited_Controlled with null record;

        procedure Initialize (X : in out Rec1);
        procedure Finalize (X : in out Rec1);

        procedure Initialize (X : in out Rec2);
        procedure Finalize (X : in out Rec2);

        type Rec4 is new Rec0 with record
           Comp2 : Rec2;   -- no access discriminant
        end record;

    end Pak1;


    with Pak1;
    procedure Test1 is     -- related to c760012.a
        X : Pak1.Rec4;
    begin
        null;
    end Test1;


    with Ada.Text_IO;
    package body Pak1 is

        procedure Initialize (X : in out Rec1) is
        begin
            Ada.Text_IO.Put_Line ("Initialize Rec1");
        end Initialize;

        procedure Finalize (X : in out Rec1) is
        begin
            Ada.Text_IO.Put_Line ("Finalize Rec1");
        end Finalize;


        procedure Initialize (X : in out Rec2) is
        begin
            Ada.Text_IO.Put_Line ("Initialize Rec2");
        end Initialize;

        procedure Finalize (X : in out Rec2) is
        begin
            Ada.Text_IO.Put_Line ("Finalize Rec2");
        end Finalize;

    end Pak1;

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

Questions? Ask the ACAA Technical Agent