CVS difference for ais/ai-00350.txt

Differences between 1.1 and version 1.2
Log of other versions for file ais/ai-00350.txt

--- ais/ai-00350.txt	2003/09/19 01:42:28	1.1
+++ ais/ai-00350.txt	2003/10/29 22:54:13	1.2
@@ -3605,3 +3605,383 @@
 
 ****************************************************************
 
+From: Robert A. Duff
+Sent: Sunday, October 19, 2003  3:48 PM
+
+Sorry to reraise this issue, which some folks may be tired of talking
+about.  But a few weeks ago Randy told me he was filing an AI on the
+subject, and he asked me to address a couple of issues I had failed to
+address in my previous diatribes.  Since it's now an AI, I'm including
+the arg mailing list -- I *hope* that's the right thing to do.
+
+[For those who haven't seen this long thread, somebody asked whether a
+user-defined Allocate routine needs to ensure that every call returns a
+distinct Address, even if the size to be allocated is zero.  Tucker then
+suggested that X = Y should be (or is) allowed to return either True or
+False in some cases.  Several different suggestions for *which* cases
+were proposed.  I claimed that equality on access types is defined in
+terms of object identity, not addresses, and that it would damage the
+language to change that fact.]
+
+First of all, Tucker *seemed* to be claiming that 4.5.2(12) *could* be
+interpreted to mean that zero-sized objects are a special case.  It says:
+
+    Two access-to-object values are equal if they designate the same
+    object, or if both are equal to the null value of the access type.
+
+Since that paragraph does not contain the word "zero" or "size" or
+anything else related to this issue, it seems to be sheer fantasy to
+claim that it could be interpreted as saying anything special about
+zero-sized objects.  Surely, if the author had intended to have a kludgy
+special case for zero-sized objects, there would some words to that
+effect in the paragraph.  (Note that in the very *next* paragraph, there
+*is* a kludgy special case for implementation reasons, and as expected,
+this is stated explicitly.  In fact it's stated twice (4.5.2(13), and
+3.10.2(39)).)
+
+I strongly object to the idea that this paragraph is totally ambiguous,
+and that therefore the ARG is free to fiddle with it arbitrarily.
+
+If Tucker is not making that claim, he should clarify what he *is*
+claiming.  Otherwise, he should buy me a new pair of eyeglasses, because
+I can't see the word "zero" that he discerns in para 12.  ;-)
+
+Seriously, this paragraph seems to be one of the clearest in the RM.
+It means:
+
+    Two access-to-object values are equal if AND ONLY IF they designate
+    the same object, or if both are equal to the null value of the
+    access type.  That is, IF AND ONLY IF the objects have the same
+    *identity* (in the nonnull case).
+
+We briefly discussed that "if" might mean "if but not necessarily only
+if", but I believe I refuted that idea, using Robert's rule.  So "if"
+here must mean "if and only if" (as stated in Chapter 1).  It cannot
+possibly be "interpreted" to mean "if, but not blah blah zero-sized blah
+blah discriminants...".  I can understand that Tucker (and Randy, and an
+earlier not-yet-debugged version of Pascal ;-)) don't *like* what it
+says.  But to claim that it could be interpreted to say something other
+than what it obviously says seems like an unfair debating tactic -- an
+attempt to pretend that a proposed language change isn't really a
+change.
+
+If Tucker or somebody wants to claim that this paragraph could be
+interpreted in some way, they have to point to some actual words in the
+RM -- it's not good enough to say, "Well, *I* don't understand that
+paragraph -- it seems utterly ambiguous to me."
+
+Perhaps you meant "Perhaps the original author didn't think about the
+zero-sized case when writing this paragraph."  Now *that* I could
+believe (although I know *I* thought about it -- I've known for 20 years
+that Ada requires a special zero check in some allocators!).
+
+----
+
+Now Tucker *did* point out one hole: If one or both access values being
+compared designate an object that no longer exists (because of
+Unchecked_Deallocation, or leaving the scope of an aliased stack
+object), then that paragraph, if it means anything at all, means "="
+returns False (because they don't designate the same object -- it's been
+freed, so they don't designated *any* object).  That's clearly not what
+we want; we want to allow True in this case.
+
+I agree that this is a hole.  However, I object to pretending that the
+hole is wider than it is.  Patching this hole in no way requires adding
+new special cases about zero-sized objects.  The latter would be a
+language change, not a patch to an existing hole.
+
+Tucker also pointed out that this case is *not* declared erroneous, nor
+is it declared "wildly erroneous".  ;-)  This is true.  However, any
+program that compares pointers to deallocated objects necessarily has a
+bug, because it is impossible to get any useful information from such a
+comparison.  Usually, in Ada, we like compilers to catch bugs (either at
+compile time or at run time).  However in this and a few other cases, we
+do not wish to require that, because it would greatly harm efficiency.
+
+It would seem useful if an implementation chose to detect such bugs.
+Most implementations can't reasonably do that, but I see no reason to
+*forbid* such detection.  It would be feasible to detect such bugs in an
+implementation that has garbage-collection support, for example.
+Therefore, I suggest that the best fix would be to say that "=" when one
+or both access values designates a nonexistent (deallocated) object is a
+bounded error: it might return either True or False, or it might raise
+Program_Error.
+
+In any case, the wording belongs in Chap 13, not Chap 4.
+
+----
+
+The other point Randy asked me to address is
+Address_To_Access_Conversions.  If there is a hole in the semantics of
+Address_To_Access_Conversions, then it should be patched in Chap 13.
+Using some weird issue related to Address_To_Access_Conversions to
+drive the high-level semantics of access equality is a case of the tail
+wagging the dog.
+
+I don't think there *is* a hole in Address_To_Access_Conversions; please
+correct me if I'm wrong.  Address_To_Access_Conversions does whatever it
+does, and that depends on the run-time model chosen by the
+implementation.  For example, if a garbage collector is moving things
+around in memory, Address_To_Access_Conversions might have some pretty
+weird behavior -- that's the programmer's problem.  Contrast this with
+access equality, which must return the right answer even if the GC is
+moving things around.  People who implement GC's know how to accomplish
+this (even in an incremental GC).
+
+If there *is* a hole in Address_To_Access_Conversions, please explain
+what it is.  And we can fix it in Chap 13.
+
+Whether or not there is such a hole, there is certainly no need for
+4.5.2(12) to mention Address_To_Access_Conversions.  Chapter-13-ish
+features (Address_To_Access_Conversions, Unchecked_Conversion, Address
+clauses, etc) can violate *any* run-time rule in the whole manual.  The
+entire RM is written with that assumption.  For example, we say that
+discriminants can't change.  Of course, they *can* change if you use
+Chapter-13-ish features, but we don't pollute the section on
+discriminants by chatting about that.
+
+----
+
+Now I finally get to the *real* issue: what *ought* the RM say about "="
+on access-to-zero-sized objects?
+
+Tucker proposes (as I understand it), that "=" should be allowed to
+return either True or False if *both* of the access values designate
+distinct zero-sized objects.
+
+I think Tucker has failed to address some points I made earlier.
+
+The claim is that the above permission eliminates some distributed
+overhead.  For example, an allocator might maintain a pointer to the
+next-to-be-allocated location, and increment that by the size of the
+object, which might be zero.  Thus two successive Allocates might return
+the same Address.  But this implementation is wrong, even with the above
+permission, because it would cause "=" to return True when just *one* of
+the objects is zero-sized; the next-allocated one might not be zero
+sized.
+
+Do you propose to allow either True or False when just *one* of the two
+objects is zero-sized?  That would be even worse than breaking object
+identity!  It would break the principle that "X = Y" implies
+"X.all = Y.all" (if non-null).  I strongly object to a language in which
+X.all = "Hello, world", and Y.all = "", yet X = Y!  (Worse, "...yet X
+*might* equal Y.")
+
+----
+
+Another point Tucker failed to address is that if you claim that
+equality of zero-sized objects is somehow evil programming practise, the
+burden of proof is on you.  You've given no reason why a programmer
+*shouldn't* use "=" in this case.
+
+Suppose I say, if X contains the integer number 1_259_792_008, and Y
+contains the number 7_992_829, then X = Y can return either True or
+False.  After all, this is an extremely rare thing to do; I've never run
+across these numbers in all my life of programming.  It's an unimportant
+case -- I'll bet if a compiler had this bug, nobody would notice.
+
+Well, that's not good enough.  I can't just say it's rare.  I can't just
+say it's an unimportant case.  I can't challenge someone to produce a
+useful program containing comparison of those numbers.  I have to give
+some logical argument that this is poor programming practise; that
+there's something *special* about those particular numbers that should
+logically make them incomparable.
+
+Tucker has said he doesn't think the zero-sized case is important.
+But to change the language in this way, I claim he has to show what's
+special about that case that makes it fundamentally wrong to use "=".
+(In fact, Nick showed just the opposite in his example.)
+
+----
+
+And, oh by the way, we should address the original question.  I think
+the appropriate change would be to forbid implementations from passing
+zero as the size to Allocate.  This would make it clear that the zero
+check needs to happen at the call site of Allocate (where it can often
+be optimized away), and that programmers can portably assume that
+user-defined Allocate need not check for zero.  [I think the RM already
+says this, but the argument is subtle.]
+
+Randy made a point related to this, which I have so far failed to
+address: he said something about direct calls to Allocate (not via
+"new").  Well, I think that's a red herring.  The RM doesn't say
+anything about what Allocate must do.  If you call it directly, it does
+whatever it does.  The RM just says that *if* Allocate obeys a certain
+contract, and *if* it is called via "new", then certain things happen.
+There is nothing in the RM that forbids doing the zero check as part of
+"new" rather than as part of Allocate, and in fact that implementation
+choice is preferable, which is why I advocate requiring it.
+
+----
+
+These things should be enforced by ACATS!
+
+****************************************************************
+
+From: Robert A. Duff
+Sent: Sunday, October 19, 2003  4:46 PM
+
+I wrote:
+
+> But a few weeks ago Randy told me he was filing an AI on the
+> subject, and he asked me to address a couple of issues I had failed to
+> address in my previous diatribes.
+
+How's that for passing the blame?  I refuse to take proper
+responsibility for my own actions, and blame Randy.  Sorry,
+Randy.   ;-)
+
+Randy did say that he might be "sticking a branch into a beehive".
+;-)
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Sunday, October 19, 2003  7:05 PM
+
+[For those who haven't seen this long thread, somebody asked whether a
+user-defined Allocate routine needs to ensure that every call returns a
+distinct Address, even if the size to be allocated is zero.  Tucker then
+suggested that X = Y should be (or is) allowed to return either True or
+False in some cases.  Several different suggestions for *which* cases
+were proposed.  I claimed that equality on access types is defined in
+terms of object identity, not addresses, and that it would damage the
+language to change that fact.]
+
+I strongly agree with this, trying to kludge up equality for some implementor
+convenience here for zero sized objects is an unjustified change in the
+language.
+
+****************************************************************
+
+From: Robert I. Eachus
+Sent: Sunday, October 19, 2003  8:50 PM
+
+I also agree that there is nothing currently broken here, and trying to find
+wiggle room via appeals to cases where Unchecked_Deallocation has been called
+is wrong.  If the access value was set to null by Unchecked_Deallocation, that
+case is clearly covered by the current wording.  If a user maintains a copy of
+an access value X that is not cleared by Unchecked_Deallocation, of course
+tests for equality of X and Y may return true or false when Y is a different
+access value.
+
+In fact, this reminds me of a discussion I just had on c.l.a. The actual
+subtype of the Object parameter in instantiations of Unchecked_Deallocation is
+really useless.  (Except that it forbids Unchecked_Deallocation for
+access-to-constant types.)  Should the compiler be allowed to ignore calls to
+an instance of Unchecked_Deallocation if the subtype I used in the
+instantiation was of zero length?  Of course not!  The fact that the subtype in
+the allocation or deallocation was of zero length should have no effect on the
+language rules.
+
+Same applies here.  If I want to use access types as laundary tickets and
+ignore the data in the designated type, the rules for access types should still
+prevent me from accidentally giving out two identical laundary tickets.  (Yes,
+I know, if I deallocate something and there are still live access values
+around, I am headed for trouble.  But I would be anyway if I didn't make the
+laundry tickets limited so users couldn't duplicate them. ;-)
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Monday, October 19, 2003 12:11 PM
+
+> Sorry to reraise this issue, which some folks may be tired of talking
+> about.  But a few weeks ago Randy told me he was filing an AI on the
+> subject, and he asked me to address a couple of issues I had failed to
+> address in my previous diatribes.  Since it's now an AI, I'm including
+> the arg mailing list -- I *hope* that's the right thing to do.
+
+No, you should never cross-post between ARG and Ada-Comment. There are a
+number of reasons for this:
+-- You're making a private e-mail list's address public by so doing. That
+could lead to people trying to post to ARG that aren't members;
+-- Most of us are on both lists. By cross-posting, we get the messages
+twice. Those of us who aren't on both lists have decided to stay out of
+public technical discussions, and thus have decided to avoid the discussion
+until it comes up on the ARG agenda.
+-- By bringing another group into the middle of the discussion, we end up
+having to rehash all of the arguments again (which is especially annoying
+given the fact that Bob seems to want to win the argument by sheer volume of
+messages. :-)
+
+As happened the last time, I can't answer this whole message. But a quick
+scan showed a couple of disagreements:
+
+> Tucker also pointed out that this case is *not* declared erroneous, nor
+> is it declared "wildly erroneous".  ;-)  This is true.  However, any
+> program that compares pointers to deallocated objects necessarily has a
+> bug, because it is impossible to get any useful information from such a
+> comparison.
+
+That's not true. It is useful to compare such objects against null, and
+indeed that ought to work properly. We use that when streaming in the
+symboltable in the Janus/Ada compiler -- if a pointer is not null, we read
+another object from the stream. If it is null, there is no object to read
+in. This seems to be a generally useful technique, and we don't want to lose
+it.
+
+> Usually, in Ada, we like compilers to catch bugs (either at
+> compile time or at run time).  However in this and a few other cases, we
+> do not wish to require that, because it would greatly harm efficiency.
+
+> It would seem useful if an implementation chose to detect such bugs.
+> Most implementations can't reasonably do that, but I see no reason to
+> *forbid* such detection.  It would be feasible to detect such bugs in an
+> implementation that has garbage-collection support, for example.
+> Therefore, I suggest that the best fix would be to say that "=" when one
+> or both access values designates a nonexistent (deallocated) object is a
+> bounded error: it might return either True or False, or it might raise
+> Program_Error.
+>
+> In any case, the wording belongs in Chap 13, not Chap 4.
+
+Thus, I totally object to this wording. I'm not against making this a
+bounded error in general, but the compare against null case should not be an
+error (or undefined, for that matter).
+
+> ----
+>
+> The other point Randy asked me to address is
+> Address_To_Access_Conversions.  If there is a hole in the semantics of
+> Address_To_Access_Conversions, then it should be patched in Chap 13.
+> Using some weird issue related to Address_To_Access_Conversions to
+> drive the high-level semantics of access equality is a case of the tail
+> wagging the dog.
+
+There is no hole in Address_to_Access_Conversions (AAC). The problem is your
+insistence on an object-based model for equality compares, with no wiggle
+room.
+
+If you have such a comparison, you then have to say what object the result
+of an AAC is. Otherwise, you have no basis to decide what the answer from
+such a comparison is. And, as I showed earlier, any answer to this question
+essentially requires that all objects (not just aliased ones) have to have a
+unique id. The only way to do that is to disallowing zero-sized objects -
+and that has a runtime cost, especially for array slices.
+
+...
+> Randy made a point related to this, which I have so far failed to
+> address: he said something about direct calls to Allocate (not via
+> "new").  Well, I think that's a red herring.  The RM doesn't say
+> anything about what Allocate must do.  If you call it directly, it does
+> whatever it does.  The RM just says that *if* Allocate obeys a certain
+> contract, and *if* it is called via "new", then certain things happen.
+> There is nothing in the RM that forbids doing the zero check as part of
+> "new" rather than as part of Allocate, and in fact that implementation
+> choice is preferable, which is why I advocate requiring it.
+
+I very much dislike having the specification of a routine fail to indicate
+its contract. Moreover, any good Ada programmer will include a check for any
+invariants in a subprogram's implementation; the only check that they would
+ever omit would be ones implied by the subprogram's specification. You in
+fact said that you did this yourself. So the net effect is to require a
+double check, both of which are often dynamic and thus will require code.
+Allocations are common, so requiring the check at the point of the call will
+add a substantial amount of code to the system. (Our experience is that
+around 50% of the allocations in the program text are dynamically sized -
+there are a lot of allocations of generic formal parameters and of
+dynamically sized arrays in the programs that we look at.)
+
+****************************************************************
+

Questions? Ask the ACAA Technical Agent