Version 1.1.1.1 of ais/ai-00146.txt

Unformatted version of ais/ai-00146.txt version 1.1.1.1
Other versions for file ais/ai-00146.txt

!standard 07.06.01 (04)          97-11-14 AI95-00146/00
!class confirmation 96-06-06
!status No Action 10-0-2 97-11-14
!status received 96-06-06
!priority Low
!difficulty Easy
!subject Controlled Components are Finalized
!summary 96-06-06
!question 96-06-06
!response 96-06-06
!appendix

!section 7.6.1(04)
!subject Controlled components
!reference RM95-7.6.1(4)
!reference RM95-7.6.1(9)
!from Ted Giering 96-4-5
!reference 96-5557.a Ted Giering 96-5-16>>
!discussion

        This question applies to controlled components of composite objects.
        If a component is successfully initialized, must it be finalized on
leaving it's master?  The LRM seems to indicate that only objects are
guaranteed to be finalized once they are successfully initialized
(7.6.1(4)).  Components are addressed in 7.6.1(9), which says that
they will be finalized after the overall object.  It does not say that
an initialized component is guaranteed to be finalized.
        I found this surprising, since it would appear to limit the kind
of controlled type that could be used safely as a component.  If the
Initialize procedure of a controlled type allocated storage and
depended on the Finalize procedure to reclaim the storage, use of the
type as a component could cause a storage leak.
        Consider the following example.  It creates a controlled type and
an array, both of which have controlled components.  All of the
Initialize procedures increment a counter, as do all of the Finalize
procedures.  In addition, the Initialize procedure for the component
type raises an exception when called for the third time, preventing
either object from completing its initialization, but only after the
successful initialization of two of its components.  When
compiled with GNAT 3.03 under DEC OSF/1 V3.2 (Rev. 214), the output
is:

Number of Initialize calls:  2
Number of Finalize calls:  0
Number of Initialize calls:  2
Number of Finalize calls:  0

GNAT would appear to implemented according to this reading of the LRM,
controlling Initialize/Finalize call pairs at the object level only.
Is this the intent of the LRM?

-- File: init.ads
with Ada.Finalization;
package Init is

        Init_Error : exception;

        Init_Count, Final_Count : Integer := 0;

        type Inner is new Ada.Finalization.Controlled with null record;

        procedure Initialize (Object : in out Inner);
        procedure Finalize (Object : in out Inner);

        type Outer is new Ada.Finalization.Controlled with record
                I1, I2 : Inner;
        end record;

        procedure Initialize (Object : in out Outer);
        procedure Finalize (Object : in out Outer);

        subtype Idx is Integer range 1..10;
        type Controlled_Array is array (Idx) of Inner;

end Init;

-- File: init.adb
package body Init is

        procedure Initialize (Object : in out Inner) is
        begin
                Init_Count := Init_Count + 1;
                if Init_Count = 2 then
                        raise Init_Error;
                end if;
        end Initialize;

        procedure Finalize (Object : in out Inner) is
        begin
                Final_Count := Final_Count + 1;
        end Finalize;

        procedure Initialize (Object : in out Outer) is
        begin
                Init_Count := Init_Count + 1;
        end Initialize;

        procedure Finalize (Object : in out Outer) is
        begin
                Final_Count := Final_Count + 1;
        end Finalize;

end Init;

-- File: init_test.adb
with Init; use Init;
with Text_IO; use Text_IO;
procedure Init_Test is

        procedure Inner_Proc is
                O : Outer;
        begin
                null;
        end Inner_Proc;

        procedure Array_Proc is
                A : Controlled_Array;
        begin
                null;
        end Array_Proc;

        procedure Inner_Caller is
        begin
                Inner_Proc;
                raise Init_Error;
        exception
        when Init_Error =>
                Put_Line ("Number of Initialize calls: " &
                        Integer'Image (Init_Count));
                Put_Line ("Number of Finalize calls: " &
                        Integer'Image (Final_Count));
        end Inner_Caller;

        procedure Array_Caller is
        begin
                Array_Proc;
                raise Init_Error;
        exception
        when Init_Error =>
                Put_Line ("Number of Initialize calls: " &
                        Integer'Image (Init_Count));
                Put_Line ("Number of Finalize calls: " &
                        Integer'Image (Final_Count));
        end Array_Caller;

begin
        Init_Count := 0;
        Final_Count := 0;
        Inner_Caller;
        Init_Count := 0;
        Final_Count := 0;
        Array_Caller;
end Init_Test;



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

!section 7.6.1(04)
!subject Controlled components
!reference RM95-7.6.1(4)
!reference RM95-7.6.1(9)
!reference 96-5557.a Ted Giering 96-5-16
!from Bob Duff
!reference 96-5558.a Robert A Duff 96-5-17>>
!discussion

>       This question applies to controlled components of composite objects.
>       If a component is successfully initialized, must it be finalized on
> leaving it's master?

Yes.

>...  The LRM seems to indicate that only objects are
> guaranteed to be finalized once they are successfully initialized
> (7.6.1(4)).  Components are addressed in 7.6.1(9), which says that
> they will be finalized after the overall object.  It does not say that
> an initialized component is guaranteed to be finalized.

A component is an object.  All objects, including components, are
finalized if they were successfully initialized.

> GNAT would appear to implemented according to this reading of the LRM,
> controlling Initialize/Finalize call pairs at the object level only.
> Is this the intent of the LRM?

No.  It looks like a bug in GNAT, to me.

Note that in your test program, an exception is raised during the second
initialization (for each sub-test), so only one component is
*successfully* initialized.  This component should be finalized, but the
other(s) should not, and the containing object should not.

>       procedure Inner_Caller is
>       begin
>               Inner_Proc;
>               raise Init_Error;

It looks like it never gets to this raise_statement, since Inner_Proc
propagates Init_Error.  (Unless I'm misreading the test -- I didn't
study it carefully.)

- Bob


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

!section 7.6.1(04)
!subject Controlled components
!reference RM95-7.6.1(4)
!reference RM95-7.6.1(9)
!reference 96-5557.a Ted Giering 96-5-16
!reference RM95-3.3(12)
!from Keith Thompson 96-05-17
!reference 96-5562.a Keith Thompson 96-5-17>>
!discussion

>         If a component is successfully initialized, must it be finalized on
> leaving it's master?  The LRM seems to indicate that only objects are
> guaranteed to be finalized once they are successfully initialized
> (7.6.1(4)).  Components are addressed in 7.6.1(9), which says that
> they will be finalized after the overall object.  It does not say that
> an initialized component is guaranteed to be finalized.

Yes it does, since components are objects.  RM95-3.3(12) says that "a
component, slice, or view conversion of another object" is an object.
The note in AARM-7.6.1(4.a) specifically says that the set of objects
to be finalized includes subcomponents.


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

Questions? Ask the ACAA Technical Agent