CVS difference for ais/ai-00147.txt

Differences between 1.9 and version 1.10
Log of other versions for file ais/ai-00147.txt

--- ais/ai-00147.txt	2002/02/07 04:56:41	1.9
+++ ais/ai-00147.txt	2002/03/12 01:38:49	1.10
@@ -1,5 +1,6 @@
-!standard 07.06    (21)                               02-02-06  AI95-00147/08
+!standard 07.06    (21)                               02-02-25  AI95-00147/09
 !class binding interpretation 96-06-06
+!status ARG Approved 7-0-0  02-02-12
 !status work item 99-04-20
 !status ARG Approved 6-0-2  99-03-26
 !status work item 98-04-01
@@ -18,32 +19,8 @@
 paragraphs of the Standard.
 
 For non-limited controlled types, the implementation permission of
-RM-7.6(18-21) is extended as follows:
+RM-7.6(18-21) is extended.
 
-An implementation is permitted to omit implicit Initialize, Adjust and
-Finalize calls and associated assignment operations on an object of
-non-limited controlled type if
-  a) the implicit Initialize call does not affect the external effect of any
-      program execution, and
-  b) any usage of the value of the object after the implicit Initialize or
-     Adjust call and before any subsequent Finalize call on the object
-     does not affect the external effect of any program execution, and
-  c) after the omission of such calls and operations, any execution of
-     the program that executes an Initialize or Adjust call on an object
-     or initializes an object by an aggregate will also later execute a
-     Finalize call on the object and will always do so prior to assigning
-     a new value to the object, and
-  d) the assignment operations associated with the omitted Adjust calls
-     are also omitted.
-This permission applies to Adjust and Finalize calls even if the
-implicit calls have additional external effects.
-
-The last sentence of 7.6(21) is amended to include the omission of the
-finalization of the anonymous object (along with the adjustment) and to
-exclude the optimization when there are any access values designating
-the anonymous object as a whole.
-
-
 !question
 
 RM-7.6(18-21) give implementations permission to eliminate certain calls
@@ -59,7 +36,7 @@
   end;                  -- Finalize(X)
 
 Are the calls really needed for an obviously "dead" variable ?  [No, unless
-Initialize is user-defined and has an external effect.]
+Initialize is user-defined.]
 
 Second example:
 
@@ -76,7 +53,7 @@
 the execution of the first assignment and its implicit calls, merely for
 the sake of potential side-effects of these calls ? [No]
 Do we really have to Initialize and immediately thereafter Finalize X ? [No,
-unless Initialize is user-defined and has an external effect.]
+unless Initialize is user-defined.]
 
 
 Third example:
@@ -146,18 +123,18 @@
 to the target object as part of the assignment without re-adjusting so
 long as the anonymous object has no aliased subcomponents and there are no
 access values designating the anonymous object as a whole. The anonymous
-object is then finalized."
+object is not finalized if this permission is used."
 
 Add a new bulleted paragraph after 7.6(21):
 
 Furthermore, an implementation is permitted to omit implicit
 Initialize, Adjust and Finalize calls and associated assignment
 operations on an object of non-limited controlled type if
-  a) the implicit Initialize call does not affect the external effect of any
-      program execution, and
+  a) the implicit Initialize call invokes an Initialize procedure which is not
+     user-defined, and
   b) any usage of the value of the object after the implicit Initialize or
      Adjust call and before any subsequent Finalize call on the object
-     does not affect the external effect of any program execution, and
+     does not have some effect on the external interactions of the program, and
   c) after the omission of such calls and operations, any execution of
      the program that executes an Initialize or Adjust call on an object
      or initializes an object by an aggregate will also later execute a
@@ -311,7 +288,7 @@
 always eliminate single pairs.  It is fairly easy to do in a compiler,
 but hard to describe in these terms in a language definition.
 
-The words in the !summary therefore capture the bounds of the
+The words in the !wording therefore capture the bounds of the
 optimization by its externally visible effects.
 
 Finally, the !question raises an issue with the last sentence of
@@ -1476,3 +1453,535 @@
 					Randy.
 
 ****************************************************************
+
+From the minutes of Meeting 15:
+
+Tucker complains about effect of Initialize; the minutes of the previous
+meeting say that this should simply be user-defined. The group agrees, change
+bullet (a) in the wording and summary to say the Initialize is not
+user-defined.
+
+   "If the Initialize procedure is not user-defined, and"
+
+Bullet (b) should use the same wording as 11.6(5) to describe the external
+effect.
+
+   "some effect on the external interactions of the program".
+
+Simplify the summary. End at "is extended."
+
+Approve with changes: 7-0-0
+
+****************************************************************
+
+From: 	Randy Brukardt
+Sent: 	Monday, February 25, 2002  8:46 PM
+
+While making the changes from the recent ARG meeting, I noticed a couple of
+problems with the wording of AI-147.
+
+First, we changed bullet (a) to:
+
+   "If the Initialize procedure is not user-defined, and"
+
+Unfortunately, these bullets are all "ands". This statement appears to make it
+incorrect to optimize Adjust/Finalize pairs when the Initialize procedure is
+not user-defined, which clearly was not our intent. I changed it to:
+
+   "the implicit Initialize call calls an Initialize procedure which is not
+    user-defined, and"
+
+which is closer to Erhard's original wording. But it is a bit awkward (not as
+bad as "affect that effects"!), suggestions are welcome.
+
+The other problem is with the change to 7.6(21). Erhard's wording was:
+
+   "If an anonymous object is created, the implementation may move its value to
+   the target object as part of the assignment without re-adjusting so long as
+   the anonymous object has no aliased subcomponents and there are no access
+   values designating the anonymous object as a whole. The anonymous object is
+   then finalized."
+
+But the last sentence is exactly backwards of the discussion: if no extra
+Adjust call is made, we certainly don't want the extra Finalize call happening.
+I've changed it to:
+
+   "If an anonymous object is created, the implementation may move its value to
+   the target object as part of the assignment without re-adjusting so long as
+   the anonymous object has no aliased subcomponents and there are no access
+   values designating the anonymous object as a whole. The anonymous object is
+   not finalized if this permission is used."
+
+This is also a bit awkward. Suggestions are again welcome.
+
+****************************************************************
+
+From: Erhard Ploedereder
+Sent: Monday, March 4, 2002  12:35 PM
+
+The re-write of the last sentence of 7.6(21) is WRONG in my opinion.
+If the anon. object is created, it better be finalized.
+I'll think about it some more, but I wanted to raise a flag now.
+
+****************************************************************
+
+From: Erhard Ploedereder
+Sent: Monday, March 4, 2002   5:15 PM
+
+Now I thought about it :-)  and I object STRONGLY to:
+
+> The anonymous object is not finalized if this permission is used."
+
+This temporary object has been created, has been filled with values AND
+HAS BEEN ADJUSTED. (Read the (old and new) sentence carefully: It talks
+about the value of the temp, which got there by canonical semantics, i.e.,
+with adjustment, not about the value of the source object.) The permission
+merely applies to the second adjust that would normally occur as part of
+the value transfer to the target object.
+
+Why this object should not be finalized is completely beyond me.
+It would be a major bug.
+
+Now, you could start discussing whether the first Adjust on the Temp is
+necessary. I wondered, too (but would not want to open this topic again).
+Even in that case, I would insist on a finalization. There are several
+other anon. objects (e.g., 7.6.1(13)) that never are adjusted, but certainly
+finalized.
+
+-----------------------
+
+If the change along the lines of
+   "If the Initialize procedure is not user-defined, and"
+was merely caused by the "affect the external effect" you could make
+that "influence the external effect" :-)
+And Randy is right: the above rewrite is wrong. His rewrite of the
+rewrite is the correct one, albeit awkward. It would read a little
+less awkward with "calls" replaced by "invokes".
+
+****************************************************************
+
+From: 	Tucker Taft
+Sent: 	Monday, March 4, 2002 1:11 PM
+
+I think Randy has it right.  If the anonymous object is moved to
+the target location without re-adjustment, then it is really not
+a separate object, it is more an object whose address has changed.
+You only want to finalize it once, and presumably the target location
+will be finalized eventually.
+
+****************************************************************
+
+From: Erhard Ploedereder
+Sent: Monday, March 4, 2002   5:43 PM
+
+I see your point (and its consequences). But then, the model of this
+optimization feels wrong...
+
+The rule in the rewrite breaks a fundamental model that holds throughout the
+language: A controlled object, once created and "initialized" by whatever
+means, is definitely finalized. I would hate to undo this rule for a minor
+optimization.
+
+Would it not be a lot clearer to allow omission of the Adjust and Finalize
+(both or none) on the anon. object instead ?  (using the temp object not
+really as an controlled object, but as a bit bucket to avoid premature
+overwriting in the process of assigning overlapping objects)
+
+****************************************************************
+
+From: 	Tucker Taft
+Sent: 	Monday, March 4, 2002 6:05 PM
+
+Erhard Ploedereder wrote:
+
+> Now I thought about it :-)  and I object STRONGLY to:
+>
+>
+>>The anonymous object is not finalized if this permission is used."
+>>
+>
+> This temporary object has been created, has been filled with values AND
+> HAS BEEN ADJUSTED.
+
+
+This makes sure the temporary object is a "safe" copy of the
+original.
+
+ > ...
+
+ (Read the (old and new) sentence carefully: It talks
+> about the value of the temp, which got there by canonical semantics, i.e.,
+> with adjustment, not about the value of the source object.) The permission
+> merely applies to the second adjust that would normally occur as part of
+> the value transfer to the target object.
+
+
+This *eliminates* the second adjust, so we need to eliminate a
+corresponding finalize.  Which one do we eliminate, if not
+the one on the temp?
+
+I suggest we construct an example and work it through.  I am
+quite confident that if we eliminat an adjust, we need to
+eliminate a Finalize.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Tuesday, March 5, 2002  6:05 PM
+
+>  (Read the (old and new) sentence carefully: It talks
+> > about the value of the temp, which got there by canonical semantics, i.e.,
+> > with adjustment, not about the value of the source object.) The permission
+> > merely applies to the second adjust that would normally occur as part of
+> > the value transfer to the target object.
+>
+> This *eliminates* the second adjust, so we need to eliminate a
+> corresponding finalize.  Which one do we eliminate, if not
+> the one on the temp?
+
+My preference would be to get rid of this permission altogether. It almost
+never can be used (the compiler would have to prove that there are no access
+types which could designate the type), and it just isn't worth the work to keep
+it.
+
+> I suggest we construct an example and work it through.  I am
+> quite confident that if we eliminat an adjust, we need to
+> eliminate a Finalize.
+
+Here is a (pseudo-code) attempt at a reference count example (this is very
+similar to some code in Claw):
+
+    type Resource is record
+	  Cnt : Natural := 0;
+        ...; -- A resource managed by the reference count
+    end record;
+    type Resource_Access is access Resource;
+    type Ctrl_Resource is Ada.Finalization.Controlled with record
+	  Data : Resource_Access := null;
+    end record;
+    procedure Initialize (Object : in out Ctrl_Resource) is
+    begin
+        Object.Data := new Resource;
+        Object.Data.Cnt := 1;
+        -- More resource allocation.
+    end Initialize;
+    procedure Adjust (Object : in out Ctrl_Resource) is
+    begin
+        Object.Data.Cnt := Object.Data.Cnt + 1;
+    end Adjust;
+    procedure Finalize (Object : in out Ctrl_Resource) is
+    begin
+        if Object.Data /= null then
+            Object.Data.Cnt := Object.Data.Cnt - 1;
+            if Object.Data.Cnt = 0 then
+                ... -- Free resource.
+                Free(Object.Data);
+            else -- Just null out the pointer, someone else has a copy
+                 -- and will deallocate it.
+                Object.Data := null;
+            end if;
+        -- else finalized already.
+        end if;
+    end Finalize;
+
+OK, now, lets assign an object:
+
+    declare
+        A, B : Ctrl_Resource; -- A.Data.Cnt = 1 = B.Data.Cnt
+    begin
+        ...
+        B := A;
+        ...
+    end;
+
+The canonical implementation is:
+    <anon> := A; -- A.Data.Cnt = 1
+    Adjust(<anon>); -- A.Data.Cnt = 2
+    Finalize(B); -- B.Data.Cnt = 0, Data is freed.
+    B := <anon>; -- B.Data.Cnt = 2
+    Adjust(B); -- B.Data.Cnt = 3
+    Finalize(<anon>); -- B.Data.Cnt =  2
+
+B.Data.Cnt equals 2, which is right (there are two copies of the data object,
+in A and B).
+
+If the anonymous object can be eliminated, we have
+    Finalize(B); -- -- B.Data.Cnt = 0, Data is freed.
+    B := A; -- B.Data.Cnt = 1.
+    Adjust(B); -- B.Data.Cnt = 2.
+
+
+Now, if we use the bogus permission of 7.6(21):
+
+    <anon> := A; -- A.Data.Cnt = 1
+    Adjust(<anon>); -- A.Data.Cnt = 2
+    Finalize(B); -- B.Data.Cnt = 0, Data is freed.
+    B := <anon>; -- B.Data.Cnt = 2
+    Finalize(<anon>); -- Should this be here??
+
+Erhard argues that the final Finalize is needed. However, if it is there,
+B.Data.Cnt will be decremented to 1 -- but there still are two objects pointing
+at Data -- so the reference count should be 2.
+
+Therefore, it is clear that the Finalize call on the anonymous object must be
+omitted.
+
+Erhard suggests:
+>Would it not be a lot clearer to allow omission of the Adjust and Finalize
+>(both or none) on the anon. object instead ?  (using the temp object not
+>really as an controlled object, but as a bit bucket to avoid premature
+>overwriting in the process of assigning overlapping objects)
+
+Yes, this seems like a better model. (Indeed, in this model, I think that the problems that showed up in Claw with the original optimization would not appear).
+
+Let's look at the example using this model:
+
+    <anon> := A; -- A.Data.Cnt = 1
+    Finalize(B); -- B.Data.Cnt = 0, Data is freed.
+    B := <anon>; -- B.Data.Cnt = 1
+    Adjust(B); -- B.Data.Cnt = 2
+
+Yes, this gets the correct result.
+
+This model also avoids the "object as a whole" problem that the original rule
+has. That is, since the Adjust only occurs on the final object, it will have
+the correct address for the (whole) object. Thus, I don't think we need the
+"object as a whole" language.
+
+So, perhaps the rule really ought to be:
+
+"Even if an anonymous object is created, the implementation may omit adjusting
+and finalizing the anonymous object so long as the anonymous object has no
+aliased subcomponents."
+
+This rule sounds a lot better, because implementations can actually use this
+one. (I'm not sure there is any need for the "no aliased subcomponents" rule,
+either, again as we are always guarenteeing an Adjust on the final object. The
+AARM seems to indicate that is the reason for this rule.) Any comments??
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Tuesday, March 5, 2002 10:41 PM
+
+Randy Brukardt wrote:
+
+> ...
+> Therefore, it is clear that the Finalize call on the anonymous object must
+> be omitted.
+
+
+Thanks for this example.  It clearly shows the importance of
+deleting adjust/finalize in pairs.
+
+
+>
+> Erhard suggests:
+>
+>>Would it not be a lot clearer to allow omission of the Adjust and Finalize
+>>(both or none) on the anon. object instead ?  (using the temp object not
+>>really as an controlled object, but as a bit bucket to avoid premature
+>>overwriting in the process of assigning overlapping objects)
+>>
+>
+> Yes, this seems like a better model. (Indeed, in this model, I think that
+> the problems that showed up in Claw with the original optimization would not
+> appear).
+>
+> Let's look at the example using this model:
+>
+>     <anon> := A; -- A.Data.Cnt = 1
+>     Finalize(B); -- B.Data.Cnt = 0, Data is freed.
+>     B := <anon>; -- B.Data.Cnt = 1
+>     Adjust(B); -- B.Data.Cnt = 2
+>
+> Yes, this gets the correct result.
+
+
+Suppose A is a temp of some sort, such as a function call.
+Isn't there a danger that if you don't do the adjust on the <anon>
+object, that the data associated with A might be freed
+prematurely?  I suppose at this point it is very dependent
+on the order the implementation does finalization of temps.
+
+
+> This model also avoids the "object as a whole" problem that the original
+> rule has. That is, since the Adjust only occurs on the final object, it will
+> have the correct address for the (whole) object. Thus, I don't think we need
+> the "object as a whole" language.
+>
+> So, perhaps the rule really ought to be:
+>
+> "Even if an anonymous object is created, the implementation may omit
+> adjusting and finalizing the anonymous object so long as the anonymous
+> object has no aliased subcomponents."
+>
+> This rule sounds a lot better, because implementations can actually use this
+> one. (I'm not sure there is any need for the "no aliased subcomponents"
+> rule, either, again as we are always guarenteeing an Adjust on the final
+> object. The AARM seems to indicate that is the reason for this rule.) Any
+> comments??
+
+
+This does seem like a tempting approach.  In fact, we never use
+this optimization for assignment statements, since we *never*
+create temps for assignment statements.  We do use this optimization
+as part of function return.  Does it work for that context as well?
+May need some more thought...
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Wednesday, March  6, 2002  9:12 AM
+
+After more thought...
+
+I think if the anonymous object is just a holding bin, then there is
+no need to mention it at all -- it is as though it wasn't there.
+
+The more important issue is whether an object may be created and initialized
+when it is in one place, and then finalized when it is at a different address.
+Moving an object is something that certain kinds of garbage collectors do,
+and also may be something done as part of certain kinds of function return.
+
+It seems important to specify under what circumstances it is permissible to
+move an object with a controlled part between initialize/adjust and finalize.
+The rule we want, I still believe, is "no aliased subcomponents and no access
+values designating the object as a whole" or something like that.  For an
+arbitrary object it may be hard to determine whether there is an access value
+designating it, but for an anonymous object created by the compiler, that
+is not so hard to determine.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Wednesday, March 6, 2002  4:46 PM
+
+> > Let's look at the example using this model:
+> >
+> >     <anon> := A; -- A.Data.Cnt = 1
+> >     Finalize(B); -- B.Data.Cnt = 0, Data is freed.
+> >     B := <anon>; -- B.Data.Cnt = 1
+> >     Adjust(B); -- B.Data.Cnt = 2
+> >
+> > Yes, this gets the correct result.
+>
+>
+> Suppose A is a temp of some sort, such as a function call.
+> Isn't there a danger that if you don't do the adjust on the <anon>
+> object, that the data associated with A might be freed
+> prematurely?  I suppose at this point it is very dependent
+> on the order the implementation does finalization of temps.
+
+Finalizing the temp A before the Adjust(B) would be a problem. The language
+only bounds the lateness of finalization of temps, not the earliness. On the
+other hand, why would any implementation use *two* anonymous objects? For a
+function result, the returning code would be like:
+
+    -- In the function at the return statement:
+    <anon> := <local>; -- <anon>.Data.Cnt = 1.
+    Adjust(<anon>); -- <anon>.Data.Cnt = 2.
+    Finalize(<local>); <anon>.Data.Cnt = 1.
+    -- In the caller's code:
+    Finalize(B); -- B.Data.Cnt = 0, Data is freed.
+    B := <anon>; -- B.Data.Cnt = 1
+    Adjust(B); -- B.Data.Cnt = 2
+    Finalize(<anon>); -- B.Data.Cnt = 1
+
+To take advantage of Erhard's permission, you would change the code to:
+
+    -- In the function at the return statement:
+    <anon> := <local>; -- <anon>.Data.Cnt = 1
+    Finalize(<local>); -- <anon>.Data.Cnt = 0 (Oops!)
+    -- In the caller's code:
+    Finalize(B); -- B.Data.Cnt = 0, Data is freed.
+    B := <anon>; -- B.Data.Cnt = 0
+    Adjust(B); -- B.Data.Cnt = 1
+
+You're right, this doesn't work. I wouldn't have expected to be able to use
+the rule in that case, but the wording of the rest of the paragraph seems to
+imply that that was intended.
+
+I'll have to think about a wording that would avoid this.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Wednesday, March 6, 2002  5:04 PM
+
+> After more thought...
+>
+> I think if the anonymous object is just a holding bin, then there is
+> no need to mention it at all -- it is as though it wasn't there.
+
+I agree with this. It is always OK to make an "as-if" optimization; this is
+essentially the case where the compiler still makes an anonymous object, but
+simply doesn't tell anyone about it. That means Erhard's rule is unnecessary.
+
+> The more important issue is whether an object may be created and initialized
+> when it is in one place, and then finalized when it is at a different address.
+> Moving an object is something that certain kinds of garbage collectors do,
+> and also may be something done as part of certain kinds of function return.
+>
+> It seems important to specify under what circumstances it is permissible to
+> move an object with a controlled part between initialize/adjust and finalize.
+
+That's easy, NEVER. :-)
+
+Well, more accurately, it can't be done unless the compiler can prove that
+there are no possible position-dependencies (either from components,
+discriminants, or accesses to the object). This is very hard to do, so in
+practice, the answer is never.
+
+Does anyone else find this "you are allowed to Adjust the wrong object" rule
+important or useful? So far as I know, no compilers other than Tucker's use
+this permission at all. And it is clearly is very dangerous if incorrectly
+applied (as Tucker's compiler did to us with Claw).
+
+> The rule we want, I still believe, is "no aliased subcomponents and no access
+> values designating the object as a whole" or something like that.  For an
+> arbitrary object it may be hard to determine whether there is an access value
+> designating it, but for an anonymous object created by the compiler, that
+> is not so hard to determine.
+
+Actually, it is pretty hard to determine. In order to insure the that the
+anonymous object doesn't have any "access values designating the object as a
+whole", a compiler would have inspect the implementation of the Adjust
+operation (and any other operations called on the anonymous object). Because
+that is precisely what happened in Claw:
+
+    procedure Adjust (Window : in out Root_Window_Type) is
+    begin
+        -- Add this copy to the Window's clone chain:
+        Window.Sibling := Window.Data.Clone_Chain;
+        Window.Data.Clone_Chain := Window'Unchecked_Access;
+        ...
+    end Adjust;
+
+So, in order to use this rule in any form at all, you would have to have a body
+dependency on the implementation (or implementations, if the context is
+dispatching) of Adjust. (Because if Adjust changes, you would have to recheck
+whether you could do the optimization.) And if there are any subprogram calls
+in Adjust, you would have to trace them as well (and include appropriate body
+dependencies).
+
+But the point of these rules is to provide cases where you do not have to look
+into the implementation of Adjust/Finalize, etc. Since there no such case, I
+have to wonder why we have any rule at all. After all, if you are willing to
+look into Adjust to figure out it is OK, then you can do an "as-if"
+optimization where the anonymous object is logically (if not actually) deleted.
+
+So, what you've done is (re)convinced me that this rule is completely pointless
+in the current form [in the original form, it is actively harmful]. I think it
+should simply be deleted.
+
+****************************************************************
+
+From: Erhard Ploedereder
+Sent: Sunday, March 10, 2002   6:00 PM
+
+Let me add to the discussion that I would prefer to see the entire sentence
+gone. (I never was convinced that this was a meaningful permission anyway.)
+
+****************************************************************
+

Questions? Ask the ACAA Technical Agent