CVS difference for ais/ai-00083.txt

Differences between 1.7 and version 1.8
Log of other versions for file ais/ai-00083.txt

--- ais/ai-00083.txt	1999/12/10 01:13:30	1.7
+++ ais/ai-00083.txt	2000/03/27 18:17:33	1.8
@@ -415,3 +415,703 @@
 
 ****************************************************************
 
+From: John Barnes
+Sent: Sunday, March 26, 2000 2:20 AM
+
+I really want to see this initialization of aggregates discussed
+sometime. I really hate it.
+
+It is AI-197 and 83.
+
+Tucker was supposed to be giving us a lecture on the topic but
+unfortunately he will not be with us. But I note that the situation
+has Robert's disapproval as well.
+
+>Robert Dewar wrote:
+>
+>> I really dislike AI95-0083 for just the reasons given in the
+>> Kallberg note
+
+Maybe we have to put up with something (because of "null" constants in
+certain predefined packages) but we don't have to put up with exactly
+what we have at the moment.
+
+I had hoped to write something last week but we had an unexpected
+elderly relative in and out of hospital and a funeral. Well it was the
+hospitalization which was unexpected. So was the funeral. I will try
+to write something later today or tomorrow.
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Sunday, March 26, 2000 7:22 AM
+
+Here is my "lecture" on initialization-by-aggregate:
+
+> >Finalize is paired with an Initialize, an Adjust, or an aggregate
+> >evaluation.  Initialize corresponds to initialization by default,
+> >Adjust corresponds to initialization by copy (from an object with its
+> >own independent finalize), and aggregate evaluation corresponds to
+> >component-by-component initialization.
+
+I really don't know what more I could say.
+
+If those who don't "like" these AIs could be more specific, I might
+be able to expand my lecture.  I can believe there was a confused
+belief that finalize was paired with only Initialize or Adjust,
+but that is wrong.  There are three ways to initialize a controlled
+object, by default, by copy, and by component-by-component initialization.
+The third is available only when within the scope of the full
+type definition, as appropriate (*all* controlled types should be
+private, or else the "control" is pointless).
+
+Let me know if a longer lecture would be of use, and what area I
+should elaborate further.
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Sunday, March 26, 2000 7:42 AM
+
+Well I must say I have lost the thread here.
+
+Can you answer the following questions
+
+1. Does the original wording in the RM reflect your lecture? If not how
+not and why not?
+
+2. Does the AI change things wrt your lecture?
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Sunday, March 26, 2000 9:23 AM
+
+> 1. Does the original wording in the RM reflect your lecture? If not how
+> not and why not?
+
+Yes.  However, the original wording (e.g. of 7.6(1)) does not clearly spell out
+that there are three ways to initialize a controlled object, by default,
+by assignment, and component-by-component.  You must glean it from
+reading 4.3(5) which indicates that an object is created as part of
+evaluating an aggregate.
+
+> 2. Does the AI change things wrt your lecture?
+
+No.  My lecture still holds.
+
+What the AI says is that when a controlled object is initialized
+by assignment from an aggregate, rather than:
+
+  1) creating an anonymous object by evaluating the aggregate, and
+  2) assigning that anonymous object into the object being initialized
+      (with the attendant adjustment)
+  3) finalizing the anonymous object.
+
+This must be shortened to simply:
+
+  1) initializing the object directly from the component values specified
+     in the aggregate.
+
+Essentially, the "object" in which the aggregate is evaluated
+is the user specified object, rather than a separate anonymous object.
+The properties of this user-specified object are exactly like the "normal"
+anonymous objects created as part of evaluating an aggregate.
+In particular, they undergo no adjustment after evaluation of
+the aggregate, but they do need to be finalized when their lifetime
+ends.
+
+The reason for the AI is that we do not want Adjust or Finalize
+called in connection with using an anonymous object as a temporary
+holder for the aggregate value, since neither operation has necessarily
+been elaborated yet.
+
+To reemphasize the critical point, this AI does *not* create a new
+class of objects that get finalized without first having Adjust or
+Initialize called.  That class of objects already existed -- the
+anonymous objects created as part of evaluating an aggregate.
+That class of objects will continue to exist independent of how we
+end up wording this AI.  We most definitiely do not want to change
+the way aggregate objects are created and finalized.
+
+The only issue is whether the anonymous object should be created, copied,
+and then finalized for the cases when an aggregate is used to initialize
+some user-specified object.  This AI says no -- such aggregates should
+be evaluated directly into their target object, to avoid the problematic
+"early" calls on adjust and finalize.
+
+The overall "balance" equation should remain that for a given controlled type:
+
+  Number of aggregate evaluations +
+    Number of calls on Initialize + Number of calls on Adjust =
+  Number of calls on Finalize
+
+This AI does not destroy this balance.  It simply reduces the
+value by one on each side of the equation.
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Sunday, March 26, 2000 11:05 AM
+
+OK, this sounds reasonable to me, I withdraw my objection ... I am still
+a bit concerned by making this a required change, I don't see how the
+RM justifies this requirement. I see it as desirable, but how can we
+require this change to be made?
+
+****************************************************************
+
+From: John Barnes
+Sent: Sunday, March 26, 2000 3:16 PM
+
+Folks
+
+Here is a hastily written note on AI-83 as promised.
+
+I hope it makes some sort of sense.
+
+See you on Wednesday.
+
+--------
+
+AI-83 and counting objects
+
+The background to Bjorn Kallberg's note on AI-83 and
+aggregates of controlled types is that he had to give a
+course on Ada 95 to some Ada 83 programmers. One topic was
+of course controlled types. Looking for an exercise for them
+to do he came across an example in my book, (page 302 of 2nd
+edition, page 286 of 1st edition). This example declares a
+controlled type and keeps track of how many objects of the
+type are in existence and also keeps an identity number in
+each object. Here is the relevant lump of book (sorry, it's
+a bit long)
+
+   ... begin extract
+
+   As a simple example, suppose we wish to declare a type
+and keep track of how many objects (values) of the type are
+in existence and also record the identity number of each
+object in the object itself. We could declare
+
+with Ada.Finalization;  use Ada.Finalization;
+package Tracked_Things is
+   type Thing is new Controlled with
+      record
+         Identity_Number: Integer;
+         ...   -- other data;
+      end record;
+   procedure Initialize(Object: in out Thing);
+   procedure Adjust(Object: in out Thing);
+   procedure Finalize(Object: in out Thing);
+end Tracked_Things;
+
+package body Tracked_Things is
+   The_Count: Integer := 0;
+   Next_One: Integer := 1;
+
+   procedure Initialize(Object: in out Thing) is
+   begin
+      The_Count := The_Count + 1;
+      Object.Identity_Number := Next_One;
+      Next_One := Next_One + 1;
+   end Initialize;
+
+   procedure Adjust(Object: in out Thing)
+       renames Initialize;
+
+   procedure Finalize(Object: in out Thing) is
+   begin
+      The_Count := The_Count - 1;
+   end Finalize;
+
+end Tracked_Things;
+
+   In this example we have considered each value of a thing
+to be a new one and so Adjust is the same as Initialize and
+we can conveniently use a renaming declaration to provide
+the body as was mentioned in Section 12.6. An alternative
+approach might be to consider new things to be created only
+when an object is first declared (or allocated). This
+variation is left as an exercise.
+
+   The observant reader will note that the identity number
+is visible to users of the package and thus liable to abuse.
+
+We can overcome this by using a child package in which we
+extend the type. This enables us to provide different views
+of a type and effectively allows us to create a type with
+some components visible to the user and some components
+hidden.
+
+   Consider
+
+package Tracked_Things is
+   type Identity_Controlled is abstract tagged private;
+private
+   type Identity_Controlled is abstract new Controlled with
+      record
+         Identity_Number: Integer;
+      end record;
+   procedure Initialize ...
+   -- etc.
+end Tracked Things;
+
+package Tracked_Things.User_View is
+   type Thing is new Identity_Controlled with
+      record
+         ...   -- visible data
+      end record;
+end Tracked_Things.User_View;
+
+   In this arrangement we first declare a private type
+Identity_Controlled just containing the component
+Identity_Number (this component being hidden from the user)
+and then in the child package we further extend the type
+with the visible data which we wish the user to see. Note
+carefully that the type Identity_Controlled is abstract so
+objects of this type cannot be declared and moreover the
+user cannot even see that it is actually a controlled type.
+We also declare Initialize, Adjust and Finalize in the
+private part and so they are also hidden from the user.
+
+   ... end extract
+
+Bjorn asked his students to write such a package and declare
+some objects. For some students it worked and for others it
+all went wrong. It went wrong of course for those who were
+lazy and declared their objects in the same package as the
+type and thus had Initialize called before its body had been
+elaborated.
+
+AI-83 was designed so far as I am aware primarily to allow
+constants to be declared in the package defining a type
+provided they were initialized with an aggregate.  This
+seemed necessary if users were to declare packages in the
+same style for example as the type Character_Set in the
+package Ada.Strings.Maps where the declaration of the type
+is accompanied by that of a constant of the type named
+Null_Set.
+
+Personally I feel that the Ada style here is a bit dubious;
+it seems bad practice to mix up declarations of a type with
+those of objects of the type since in a sense the type is
+not properly declared until the end of the package. I would
+prefer to provide null values by declaring a function
+returning a null value. This would avoid the problems.
+(Maybe Ada is too free in its ability to do what you want
+with a package (especially with tagged types) and the
+building block approach lets us down by enabling us to build
+inappropriate structures - maybe we should have had class
+packages ...!)
+
+Now given that we have to allow the wretched user to declare
+a constant in the package defining the type then it seems we
+have to allow these wretched in situ aggregates in that
+package. However, there seems no reason to me to require
+this optimization for objects initialized with aggregates in
+other packages.
+
+It seems to me to be quite reasonable to wish to monitor the
+behaviour of a program by counting the number of times an
+object of a type has been created and indeed to know how
+many are in existence. Whether the type is private or not is
+irrelevant since the count is not in the object but hidden
+in the defining package where it is available to the author
+of the package via various subprograms .
+
+It seems that not only does the aggregate optimization
+permit an object to be declared without it being counted but
+moreover it will still get Finalized and so the count of
+objects in existence could go negative which seems very
+surprising.
+
+However, if we restricted AI-83 to just the package defining
+the type then provided the declarer of the package didn't
+declare any objects, it would be fine because all objects
+declared elsewhere would be counted properly.
+
+Well that's my view of the story, I hope it aligns with
+Bjorn's.
+
+Incidentally when I wrote the example I think I hadn't
+realized that if one declares an initialized object then
+Initialize is not called anyway but only Adjust. This means
+that one can't really count how many objects have been made
+but just how many values have been made (maybe trying to
+distinguish between values and objects is foolish and I
+should remove the exercise that asks the reader to do that
+from the book). However, it does seem reasonable to want to
+be able to count how many are in existence at any time and
+to be able to rely on the count going to zero at the end of
+the relevant scope.
+
+It's clearly an awkward topic.
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Sunday, March 26, 2000 7:20 PM
+
+> ...
+> It seems that not only does the aggregate optimization
+> permit an object to be declared without it being counted but
+> moreover it will still get Finalized and so the count of
+> objects in existence could go negative which seems very
+> surprising.
+
+As I tried to point out, with or without this optimization,
+the proper equation is:
+   Number of aggregate evaluations + Number of Inits + Number of Adjusts =
+     Number of Finalizes.
+
+If you don't count aggregates, but you do subtract one on each finalization,
+you will get a negative count.  This optimization will not change that fact.
+
+> However, if we restricted AI-83 to just the package defining
+> the type then provided the declarer of the package didn't
+> declare any objects, it would be fine because all objects
+> declared elsewhere would be counted properly.
+
+The whole notion of non-private controlled types seems like an obscure example,
+and not worth making compilers more complicated.  Having different *run time*
+semantics when inside or outside a package seems like a dangerous precedent, and
+creates questions about inline expansion, macro-based generic instantiation,
+child packages, etc.  All in all not a pretty situation.  Furthermore, as
+pointed out above, you still need to count the "wretched" aggregates, whether or
+not you perform this optimization, since they do require a balancing
+finalization.
+
+> ... However, it does seem reasonable to want to
+> be able to count how many are in existence at any time and
+> to be able to rely on the count going to zero at the end of
+> the relevant scope.
+
+And you will get the right answer if and only if you count aggregate evaluations
+as well.
+
+> ... It's clearly an awkward topic.
+
+I think the example you have is a bit "awkward."  As you have discovered, it
+really doesn't match the "normal" usage model for nonlimited controlled types.
+Nonlimited controlled types are really about having conceptual "values" that may
+involve levels of indirection.
+
+If you shifted your example over to using limited controlled types, it would
+probably make more sense, and you would only have to worry about Initialize and
+Finalize -- no Adjusts or aggregates creating new values.
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Sunday, March 26, 2000 9:16 PM
+
+<<The whole notion of non-private controlled types seems like an obscure example
+>>
+
+I find this a bit of an extraordinary statement, non-private controlled
+types are a valuable feature in my view.
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Sunday, March 26, 2000 7:25 PM
+
+Robert Dewar wrote:
+>
+> OK, this sounds reasonable to me, I withdraw my objection ... I am still
+> a bit concerned by making this a required change, I don't see how the
+> RM justifies this requirement. I see it as desirable, but how can we
+> require this change to be made?
+
+This is clearly a "binding interpretation."  The reason to require it is
+to make the usage portable.  If we wanted to make things more complicated,
+we could say that this "optimization" is only necessary prior to elaboration
+of Adjust and Finalization, and everything they might call during their execution.
+But that seems nasty to define.  If we have to make initialization-by-aggregate
+special somewhere, we might as well give it a uniform semantics everywhere, so it can
+never be the cause of an unexpected Program_Error due to an implicit call on
+Adjust or Finalize.
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Sunday, March 26, 2000 9:17 PM
+
+I find this FAR too ambitious for a binding interpretation. Sure it is
+desirable to have all compilers do the same thing, but I don't find the
+justification for this AI in the RM. I would vote against it as a binding
+interpretation, I don't see it can be supported.
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Sunday, March 26, 2000 9:44 PM
+
+> I find this FAR too ambitious for a binding interpretation. Sure it is
+> desirable to have all compilers do the same thing, but I don't find the
+> justification for this AI in the RM. I would vote against it as a binding
+> interpretation, I don't see it can be supported.
+
+I thought there was general agreement that there was a language
+bug in this area, so a binding interpretation was appropriate
+to fix the bug.
+
+The complaint with the AI was that finalizations were not always balanced
+by adjusts and initializes.  It turns out that this AI does not have any
+effect on that complaint, so that particular complaint cannot
+be fixed by fiddling with this AI.
+
+If we want to debate whether the original problem
+should be fixed, that's OK, but let's not get the
+two discussions confused.
+
+Also, if there are useful examples of non-private controlled types,
+it would be helpful to see them, so we could evaluate alternative
+solutions keeping them in mind.
+
+****************************************************************
+
+From: Pascal Leroy
+Sent: Monday, March 27, 2000 2:11 AM
+
+> I find this FAR too ambitious for a binding interpretation. Sure it is
+> desirable to have all compilers do the same thing, but I don't find the
+> justification for this AI in the RM. I would vote against it as a binding
+> interpretation, I don't see it can be supported.
+
+I am confused now.  As I recall, this topic was discussed circa 1995, and I
+don't remember seeing such a staunch opposition at the time.  Could you explain
+what new piece of information has caused you to change your mind?
+
+I don't think it is merely "desirable" for compilers to all do the same thing in
+this instance, I think it's absolutely critical, because "null" constants of a
+private type are such a common idiom, and numerous private types are controlled
+(because they contain indirections).
+
+Now maybe the resolution is to _mandate_ that Program_Error be raised in this
+instance.  I could live with that (I believe that deferred constants should not
+be in the language in the first place, so I am not going to fight for them).
+But I couldn't live with the notion that the behavior is implementation-defined.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Monday, March 27, 2000 11:12 AM
+
+> And since there is no way I can count the aggregate evaluations since
+> they occur silently, the whole quest is lost. Well that's a shame.
+
+I really don't think so; I agree with Tuck here.
+
+If your type is private, the only place that aggregates can occur is inside of
+your package. So there is no particular problem to insure that they do the right
+thing; and your users can't break that behavior.
+
+Moreover, there is a distinct advantage to having them *not* call Initialize --
+it provides a way to construct a value without having to worry about Initialize
+coming along and screwing it up. That can be handy.
+
+If you type is not private, it is not remotely bulletproof -- all that it takes
+to mess up your count is for someone to change it explicitly. So what is the
+concern? At most this gives you one more way to mess things up.
+
+> It looks more and more as if types have to be limited in order to rely
+> upon them and so user-defined assignment was a forlorn goal.
+>
+> RIP :=
+
+Baloney. Claw is mostly constructed out of types that have user-defined
+assignment with reference counting, and we have no problem with aggregates.
+We've never had a user-reported bug having to do with this finalization (except
+those related to compiler errors and the over-aggressive optimization covered by
+AI-147).
+
+We don't use aggregates in the bodies (although we could if we were careful with
+the reference counts). It is not a problem in practice. It is more interesting
+to deal with Adjust in a task-safe manner.
+
+> Do extension aggregates have any bearing on this matter?
+
+All aggregates of controlled types are extension aggregates by definition.
+Controlled is private, so a non-extension aggregate is impossible.
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Monday, March 27, 2000 7:33 AM
+
+<<Now maybe the resolution is to _mandate_ that Program_Error be raised in
+this instance.  I could live with that (I believe that deferred
+constants should not be in the language in the first place, so I am not
+going to fight for them).  But I couldn't live with the notion that the
+behavior is implementation-defined.>>
+
+There is an international standard for Ada.
+
+Vendors implement this standard, and there is a validation suite for
+this standard.
+
+If the language is modified by the ARG in a manner that is not reasonably
+justified by the standard, then we have a situation that needs examination.
+
+Remember what we are talking about here is just one thing
+
+denial or approval of validation
+
+Nothing else is important. In other words, the issue is not the label on the
+AI, it is whether a test appears for this feature.
+
+I think we are on very shaky ground if we start including mandatory tests
+for features not reasonably derivable from the intent of the RM.
+
+I just don't see this feature that the AI prescribes as being reasonably
+derivable from the intent of the RM. Yes, it is a hole. Yes, the language
+should have addressed this, but it didn't.
+
+It is one thing for the ARG to be in the business of improving the language
+by filling in the hole, it is quite another for the ARA to be in the business
+of denying validation to a vendor who implements the language as defined in
+the international standard.
+
+Traditionally, the import of the "binding interpretation" designation was
+precisely that it results in a mandatory test.
+
+I don't see that here.
+
+There are two situations
+
+1. All vendors move to implement this AI anyway, in which case it does not
+matter two hoots what designation it has.
+
+2. Not all vendors implement this AI. Now I think in practice the market place
+will put pressure on to implement it, but if the market place does not generate
+such pressure, I think it is dubious for the ARG to substitute legislation
+to replace market demand. The result of this can easily be for a vendor to
+say:
+
+  "we no longer bother with validation, since it is no longer being run by
+   the AJPO, and so has no official status in the US. Furthermore the
+   replacement validation has run amok, and is requiring compilers to
+   do things that are not required by the standard."
+
+I would far prefer this to be a non-binding interpretation, and then have
+a set of tests that tests for adherence to these NBI's reporting the results.
+
+Speaking for ACT, we will be happy to work hard on passing all these tests
+(we like to pass 100% of all the tests as you know :-) and will be happy to
+advertise that our compiler passes 100% of the NBI tests, showing that our
+technology is advancing and keeping track of things. If a competitor fails
+to implement all the ABI tests, we will be happy to point this out, but would
+feel it inappropriate to deny validation on this basis.
+
+I hope that makes my position clearer.
+
+****************************************************************
+
+From: Pascal Leroy
+Sent: Monday, March 27, 2000 8:11 AM
+
+> I think we are on very shaky ground if we start including mandatory tests
+> for features not reasonably derivable from the intent of the RM.
+>
+> I just don't see this feature that the AI prescribes as being reasonably
+> derivable from the intent of the RM. Yes, it is a hole. Yes, the language
+> should have addressed this, but it didn't.
+
+Arguments from intent are always rather bogus but...
+
+The RM states that calling an unelaborated subprogram raises Program_Error, and
+in the case that we are discussing, Adjust is clearly not elaborated.  Now there
+is this permission to optimize away some calls to Adjust, and this is what makes
+the behavior implementation-defined.
+
+It seems to me that the intent of this permission was to make it possible to
+generate better code, not to allow the declaration of null objects of controlled
+types.  Therefore, I would argue that the intent of the RM is rather clear: this
+case should raise Program_Error.
+
+In fact, I believe that the AI is not satisfactory as written: it doesn't
+completely fix the problem.  We implemented it a few years ago, and I recently
+received a complaint from a customer who was trying to write a null object for a
+type that was _not_ controlled, but had controlled subcomponents.  This case has
+exactly the same problem as the one covered by the AI (i.e., P_E is raised by a
+call to an unelaborated Adjust), but it is _not_ covered by the AI.  So if you
+have a controlled type, and for one reason or another need to wrap it into a
+record, your application suddenly fails at elaboration.
+
+> 2. Not all vendors implement this AI. Now I think in practice the market place
+> will put pressure on to implement it, but if the market place does not generate
+> such pressure, I think it is dubious for the ARG to substitute legislation
+> to replace market demand.
+
+I am not exactly happy with the notion that the semantics of Ada should be
+governed by market pressures.  The problem we are discussing is not an obscure
+cornercase of the language, it's very visible, in the sense that users are
+likely to run into (and in fact they do).  I'd much prefer an ARG resolution,
+even if that resolution is that it has to raised P_E.
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Monday, March 27, 2000 9:03 AM
+
+<<I am not exactly happy with the notion that the semantics of Ada should
+be governed by market pressures.  The problem we are discussing is not
+an obscure cornercase of the language, it's very visible, in the sense
+that users are likely to run into (and in fact they do).  I'd much
+prefer an ARG resolution, even if that resolution is that it has to
+raised P_E.
+>>
+
+But the question is, do you think we should deny validation to a vendor
+who conforms to the RM in this area!
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Monday, March 27, 2000 11:22 AM
+
+> <<I am not exactly happy with the notion that the semantics of Ada should
+> be governed by market pressures.  The problem we are discussing is not
+> an obscure cornercase of the language, it's very visible, in the sense
+> that users are likely to run into (and in fact they do).  I'd much
+> prefer an ARG resolution, even if that resolution is that it has to
+> raised P_E.> >>
+>
+> But the question is, do you think we should deny validation to a vendor
+> who conforms to the RM in this area!
+
+Well, for what it is worth, there is an Annex H test which requires
+implementation of AI-83. So at least compilers which have validated Annex H have
+indeed been held to this requirement. I've even rejected petitions on the test
+based on approved AI-83; I think Dan Lehman did so as well. So we've been
+requiring this behavior for validation for quite a while.
+
+			Randy
+			ACAA Technical Agent
+
+****************************************************************
+
+From: Randy Brukardt [Randy@RRSoftware.Com]
+Sent: Monday, March 27, 2000 11:28 AM
+
+> In fact, I believe that the AI is not satisfactory as
+> written: it doesn't completely fix the problem.  We
+> implemented it a few years ago, and I recently received a
+> complaint from a customer who was trying to write a null
+> object for a type that was _not_ controlled, but had
+> controlled subcomponents.  This case has exactly the same
+> problem as the one covered by the AI (i.e., P_E is raised by
+> a call to an unelaborated Adjust), but it is _not_ covered by
+> the AI.  So if you have a controlled type, and for one reason
+> or another need to wrap it into a record, your application
+> suddenly fails at elaboration.
+
+I thought that was what was covered by AI-197 (now folded into AI-83) and it
+ought to be covered by the Corrigendum wording for AI-83. Are you sure it isn't?
+Are you looking at the version I created last November, and not some old,
+obsolete version??
+
+****************************************************************
+

Questions? Ask the ACAA Technical Agent