!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 96-06-06 !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. ****************************************************************