Version 1.3 of acs/ac-00012.txt

Unformatted version of acs/ac-00012.txt version 1.3
Other versions for file acs/ac-00012.txt

!standard 7.6 (21)          01-09-20 AC95-00012/00
!standard 7.6.1(13)
!standard 7.6 (17.1)
!class confirmation 01-09-20
!status received no action 01-09-19
!subject Finalization called by aggregate during elaboration
!summary
!appendix

!topic Finalization called by aggregate during elaboration
!reference RM95-7.6.1(13),4.3(5),7.6(21)
!from Adam Beneschan 09-19-01
!discussion

In this example, where T is a controlled type, is it true that the
Finalize procedure on T may or may not be called during elaboration of
the declaration?

   declare
       Obj : T := (Ada.Finalization.Controlled with
                   Field1 => 1, Field2 => 2);
   begin
       <sequence-of-statements>
   end;

My understanding of the RM is that T's Finalize procedure may be
called before the sequence of statements but isn't necessarily called.
This is because the aggregate causes an anonymous object to be created
(4.3(5)), and 7.6.1(13) says that the aggregate has to be finalized
before the sequence of statements, but 7.6(21) gives implementations
permission not to create the anonymous object.

However, my understanding is contradicted by ACATS test c761011, which
contains this test:

    Normal: -- Case 1
        begin
            declare
                Obj1 : Ctrl := Create (Ident_Int (1));
                Obj2 : constant Ctrl := (Ada.Finalization.Controlled with
                                         D => False,
                                         Finalized => Ident_Bool (False),
                                         C1 => Ident_Int (2));
                Obj3 : Ctrl :=
                   (Ada.Finalization.Controlled with
                    D => True,
                    Finalized => Ident_Bool (False),
                    C2 => 2.0 * Float (Ident_Int
                                          (3))); -- Finalization: User_Error
                Obj4 : Ctrl := Create (Ident_Int (4));
            begin
                Comment ("Finalization of normal object");
                Use_It (Obj1); -- Prevent optimization of Objects.
                Use_It (Obj2); -- (Critical if AI-147 is adopted.)
                Use_It (Obj3);
                Use_It (Obj4);
            end;
            Failed ("No exception raised by finalization of normal object");
        exception
            when Program_Error =>
                if not Was_Finalized (Ident_Int (1)) or
                   not Was_Finalized (Ident_Int (2)) or
                   not Was_Finalized (Ident_Int (4)) then
                    Failed ("Missing finalizations - 1");
                end if;
            when E: others =>
                Failed ("Exception " & Exception_Name (E) &
                        " raised - " & Exception_Message (E) & " - 1");
        end Normal;

This test seems to assume that the declaration of Obj3 will *not* call
the Finalize routine, since Finalize on this particular aggregate will
raise an exception.  The Program_Error handler makes sure Obj1, Obj2,
and Obj4 were all finalized, which makes sense if the exception occurs
while trying to finalize Obj3 at the end of the block, but doesn't
make sense if the exception occurs while trying to finalize an
anonymous object when Obj3 is declared.

Is my understanding of the RM correct, or have I missed something?

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

From: Randy Brukardt
Sent: Wednesday, September 19, 2001  7:08 PM

(example deleted)

> Is my understanding of the RM correct, or have I missed something?

Sure, you've missed the Corrigendum. ACATS test C761011 was created to test
a rule added in Technical Corrigendum 1. Technical Corrigendum 1 was
published by ISO on June 1, 2001 (as ISO/IEC 8652:1995/Cor.1:2001), so it is
an official part of the ISO Ada standard by any measure. Conformity
assessment (the purpose of the ACATS) is done to the ISO standard, so the
ACATS tests reflect the rules corrected in the Corrigendum.

The rule in question is 7.6(17.1/1). The consolidated AARM (available on the
web at www.adaic.org/standards/95aarm/html/AA-7-6.html describes the reasons
behind the rule change; the entire Defect Report is also available on line
(click on the number, 8652/0022).

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

From: Adam Beneschan
Sent: Thursday, September 20, 2001  4:24 PM

Yes, I had indeed missed this new rule; thank you for pointing it out
to me.  I've been wrestling over the question over whether the wording
in 7.6(21) ought to be changed, or a note added to 4.3, to forestall
possible confusion, but I'm not sure whether this is necessary.

However, I'm now wondering if the new rule 7.6(17.1/1) is adequate in
the case of nested aggregates.  Consider this modification of the
example in 17.1/1:

   package P is
      type Dyn_String is private;
      type Dyn_Substring is private;
      Null_Substring : constant Dyn_Substring;
      ...
   private
      type Dyn_String is new Ada.Finalization.Controlled with ...
      procedure Finalize(X : in out Dyn_String);
      procedure Adjust(X : in out Dyn_String);

      type Dyn_Substring is record
         Str : Dyn_String;
         First_Index, Last_Index : Integer;
      end record;

      Null_Substring : constant Dyn_Substring :=
         (Str => (Ada.Finalization.Controlled with ...),
          First_Index => 1, Last_Index => 0);
      ...
   end P;

The declaration of Null_Substring involves two aggregates; by 4.3(5),
an anonymous object will be (conceptually) created for each.  Let's
call the anonymous object of type Dyn_Substring Anon1, and the one of
type Dyn_String Anon2.  Following 4.3(5), to create Anon1, the values
of the components are obtained and "assigned into the corresponding
components ... of the anonymous object."  One of those components is
the inner aggregate; according to 7.6(17.1/1), since the inner
aggregate has a controlled type, the implementation may not create an
anonymous object for it.  Thus, Anon2 will not be created, and the
aggregate will be built directly in Anon1.Str.

However, Dyn_Substring is not a controlled type, and therefore
7.6(17.1/1) does not apply to it.  Therefore, it's still legal (but
not required) for the compiler to create an anonymous object Anon1.
If it does so, the compiler will build Anon1 by assigning to its
components (including building the inner aggregate directly in
Anon1.Str), and then assign Null_Substring to Anon1 (which involves a
call to Adjust on Null_Substring.Str, by 7.6(16)), and then (by
7.6.1(13)) finalize Anon1, which includes (by 7.6.1(9)) finalization
of Anon1.Str; thus, Program_Error will still be raised for the same
reasons cited in 8652/0022.

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

From: Randy Brukardt
Sent: Thursday, September 20, 2001  10:28 PM

> Yes, I had indeed missed this new rule; thank you for pointing it out
> to me.  I've been wrestling over the question over whether the wording
> in 7.6(21) ought to be changed, or a note added to 4.3, to forestall
> possible confusion, but I'm not sure whether this is necessary.

7.6(21) is complete garbage; Claw (and most other O-O programs using Adjust)
couldn't be written if it was implemented literally. (Indeed, Tucker had done
exactly that, and it caused us trouble with ObjectAda for two years.) AI-00147
changes it; unfortunately, we've (the ARG) never been able to agree (and stay
agreed) on how to change it. It's on the agenda again for the upcoming meeting;
I hope it finally gets finished.

> However, Dyn_Substring is not a controlled type, and therefore
> 7.6(17.1/1) does not apply to it.  Therefore, it's still legal (but
> not required) for the compiler to create an anonymous object Anon1.
> If it does so, the compiler will build Anon1 by assigning to its
> components (including building the inner aggregate directly in
> Anon1.Str), and then assign Null_Substring to Anon1 (which involves a
> call to Adjust on Null_Substring.Str, by 7.6(16)), and then (by
> 7.6.1(13)) finalize Anon1, which includes (by 7.6.1(9)) finalization
> of Anon1.Str; thus, Program_Error will still be raised for the same
> reasons cited in 8652/0022.

I *think* this behavior is intentional. Certainly AI-0083 talks only about
extension aggregates. And I know we (the ARG) wanted to bound this requirement,
because it is a significant amount of work to get right.

The point of the rule is to make it possible to declare deferred constants of
controlled types without triggering access-before-elaboration problems. To get
it to occur with components (as in your example), it is necessary to both the
controlled type and the outer type in the same package. Thus there is an easy
work-around to avoid any problems: make sure that controlled types are not used
in components in the same package as they are declared.

So I don't think there is a problem here. But I could be wrong. :-)

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

From: Tucker Taft
Sent: Friday, September 21, 2001  7:47 AM

Well, I certainly expected that all "initialization" contexts
would require initialize-in-place for controlled subcomponents.
We should look at the wording carefully to see if this loophole
exists, and figure out whether it is worth fixing.

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

From: Randy Brukardt
Sent: Friday, September 21, 2001 12:13 PM

It certainly exists: 7.6(17.1/1) says "aggregate of a controlled type". It
would have to say something like "aggregate with any controlled parts" to cover
subcomponents. That "fix" is easy enough.

However, this is a significant change to the rule. It would have a substantial
impact on implementors, as it would extend the cost to all aggregates, not just
to extension aggregates. (The fact that the rule only applies to extension
aggregates is mentioned several times in the AI.) Moreover, it would do so to
fix a rather unlikely case. And this rule was rather controversial in the first
place, I would expect a large extension to be more so.

Is there enough interest in changing this rule to open an AI??

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


Questions? Ask the ACAA Technical Agent