!standard 07.06 (21) 99-07-28 AI95-00083/03 !class binding interpretation 95-07-27 !status Corrigendum 2000 99-07-28 !status WG9 approved 95-06-14 !status work item (letter ballot was 10-1-0) 96-06-05 !status ARG approved (subject to letter ballot) 7-0-3 95-11-01 !status received 95-07-27 !subject Aggregates of a controlled type !summary When an object of a controlled type is created and explicitly initialized with an aggregate, the aggregate is built "in place"; Finalize and Adjust are not called on the object as a whole. !question If an object of a controlled type is declared in the same package as the type, and initialized with an aggregate, is Program_Error raised? (No.) !recommendation When an object of a controlled type is created and explicitly initialized with an aggregate, the implementation must not create a separate anonymous object for the aggregate; it must create the value of the aggregate directly in the newly-created object. Thus, there is no assignment from the anonymous object to the newly-created object, so the Finalize and Adjust that would be done for that assignment are not done. !wording (See corrigendum.) !discussion Consider the following controlled type: type Dyn_String is private; Null_String : constant Dyn_String; ... private type Dyn_String is new Ada.Finalization.Controlled with record ... end record; procedure Finalize(X : in out Dyn_String); procedure Adjust(X : in out Dyn_String); Null_String : constant Dyn_String := (Ada.Finalization.Controlled with ...); Clearly, at the time when the full constant declaration for Null_String is elaborated, the bodies for Finalize and Adjust have not yet been elaborated. RM 7.6(21) gives the permission to build the aggregate directly in the target object, thereby eliminating the need for the assignment (and the associated calls on Adjust/Finalize): 21 For an aggregate or function call whose value is assigned into a target object, the implementation need not create a separate anonymous object if it can safely create the value of the aggregate or function call directly in the target object. However, it seems important to *require* this behavior, so that this kind of programming is portable (that is, it will portably work without raising Program_Error due to an access-before-elaboration from calling Adjust or Finalize before their bodies are elaborated). In other words, the first sentence of 7.6(21) should be an Implementation Requirement in the case where a new object is being created. Note that no Adjust ever takes place on an aggregate as a whole, since there is no assignment to the aggregate as a whole (AARM 4.3(5,5b)). AARM 7.6(21a) talks about this case, and says that "only one value adjustment is necessary". This is misleading. It should say that only one adjustment of each controlled *subcomponent* (if any) is necessary in this case. *No* adjustments of the object as a whole are necessary (and as suggested above, such adjustments should be disallowed). Note that this interpretation applies to all object creations, not just to object_declarations. Thus, continuing the above example, if we have: type Dyn_String_Ptr is access all Dyn_String; Null_String_Ptr: Dyn_String_Ptr := new Dyn_String'(Ada.Finalization.Controlled with ...); The aggregate must be build directly in the newly-created heap object. !corrigendum 7.06.01(20) @dinsa @xbullet @dinst @i<@s8>@hr For an aggregate of a controlled type whose value is assigned to the object created by an object declaration or allocator, the implementation must not create a separate anonymous object for the aggregate. The aggregate value must be constructed directly in the new object. In this case, Finalize and Adjust are not called on the object as a whole. !ACATS test The annex H ACATS test CXH3002 requires these semantics. However, a core C-Test should be created for this case, as this is a critical rule change. !appendix !section 7.6(21) !subject Aggregates of a controlled type !reference RM95-7.6(21) !reference AARM-7.6(21.a);6.0 !from Tucker Taft 95-07-25 !reference as: 95-5234.a Tucker Taft 95-7-25>> !discussion Consider the following controlled type: type Dyn_String is private; Null_String : constant Dyn_String; ... private type Dyn_String is new Ada.Finalization.Controlled with record ... end record; procedure Finalize(X : in out Dyn_String); procedure Adjust(X : in out Dyn_String); Null_String : constant Dyn_String := (Ada.Finalization.Controlled with ...); Clearly, at the time when the full constant declaration for Null_String is elaborated, the bodies for Finalize and Adjust have not yet been elaborated. RM 7.6(21) gives the permission to build the aggregate directly in the target object, thereby eliminating the need for the assignment (and the associated calls on Adjust/Finalize). However, it seems important to *require* this behavior, so that this kind of programming is portable (that is, it will portably work without raising Program_Error due to an access-before-elaboration from calling Adjust or Finalize before their bodies are elaborated). In other words, at least parts of 7.6(21) should be moved to an Implementation Requirement (or the Dynamic Semantics). In particular, when a constant is initialized from an aggregate of a controlled type, the aggregate should be built in place, and no Adjust or Finalize on the constant object as a whole should take place. Note that no Adjust ever takes place on an aggregate as a whole, since there is no assignment to the aggregate as a whole (AARM 4.3(5,5b)). Note that AARM 7.6(21a) talks about this case, and says that "only one value adjustment is necessary". This is misleading. It should say that only one adjustment of each controlled *subcomponent* (if any) is necessary in this case. *No* adjustments of the object as a whole are necessary (and as suggested above, such adjustments should be disallowed). -Tuck ****************************************************************