CVS difference for ais/ai-30302.txt

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

--- ais/ai-30302.txt	2004/09/14 01:25:58	1.8
+++ ais/ai-30302.txt	2004/09/17 04:44:35	1.9
@@ -17986,6 +17986,1437 @@
 ****************************************************************
 
 From: Matthew Heaney
+Sent: Tuesday, September 14, 2004  2:13 AM
+
+My comments are inline.  --MJH
+
+
+> > Q1) Find_Index returns Last_Index (Container) + 1 if the element is 
+> >not  found. This seems consistent to me (it's past the end of the 
+> >container in  a forward search), but Matt worries that First_Index 
+> >(Container) - 1  might be thought of as better. The trouble with 
+> >First_Index (Container) -  1 is that you can't put it into an object:
+...
+> The problem with Last_Index (Container) + 1 is that it may 
+> not exist, because Last_Index (Container) might be 
+> Index_Type'Last. 
+
+But Find_Index returns Index_Type'Base.  There's an implied requirement that
+Last_Index(V) < Index_Type'Base'Last, so it doesn't matther if Last_Index(V)
+= Index_Type'Last.
+
+Remember the purpose of a vector is to expand.  That's what influenced our
+decision to use an integer type as the index instead of any discrete type.
+Your argument that Last_Index(V) might equal Index_Type'Last is tantamount
+to saying that an enumeration type should be able to be used as the index
+type, but this matter has already been debated and settled.
+
+Allowing an Index_Type to be passed as a generic formal is really only
+intended to allow the user to specify the starting point of the index
+subtype range.  The ending point should be large relative to the number of
+elements typically stored in the container.  
+
+I would expect that most users would either use subtypes Natural or Positive
+as the generic actual index type.  If the starting point of your range has
+some negative values, then you could do something like:
+
+   type Index_Type is range -42 .. Integer'Pos (Integer'Last);
+or
+   type Index_Type is range -2001 .. Count_Type'Pos (Count_Type'Last);
+
+ 
+> On the other hand, we convenienty have a 
+> requirement that Index_Type'First > Index_Type'Base'First, 
+> which guarantees that First_Index (Container) - 1 does always 
+> exist (as a value of Index_Type'Base).
+>
+> I think that swings it. I suggest Find_Index returns First_Index
+> (Container) - 1 when it does not find what it is looking for.
+
+I find Randy's argument more persuasive, and hence agree with him that we
+don't need any change here.
+
+We need to affirm the semantics of Reverse_Find_Index too, since you could
+make the argument that for symmetry with Find_Index, it should return
+Index_Type'Pred (Index_Type'First).  On that other hand, you could argue
+that for consistency with Find_Index that it should return the same value.
+
+
+> > Q2) The parameters to Generic_Merge have not been made class-wide 
+> >(even  though the comments about non-primitive operations 
+> with specific 
+> >tagged  parameters mentioned for Generic_Sort hold here, 
+> too). That's 
+> >because  both parameters need to be the same type. An 
+> alternative would 
+> >be to make  them class-wide, and then have a runtime check (of the 
+> >actual tags) that  they actually are the same type. But that is not 
+> >very O-O. A third  possibility would be to repeat the type 
+> in the generic spec:
+> >   generic
+> >        type List_Type is new List with private;
+> >        with function "<" (Left, Right : Element_Type)
+> >           return Boolean is <>;
+> >     procedure Generic_Merge (Target : in out List_Type;
+> >                              Source : in out List_Type);
+> >But that is not very consistent with the rest of the specification. 
+> >Some  guidance would be helpful here.
+
+The generic formal type should probably be declared as:
+
+   type List_Type (<>) is new List with private;
+
+or possibly
+
+   type List_Type (<>) is abstract new List with private;
+
+
+> I'm uncomfortable with Generic_Sort having a classwide parameter:
+...
+> I prefer this because it makes it explicit that the list L1 
+> is being sorted /as/ a Float_Lists.List (not as a My_List, as such).
+
+
+But this argument applies to any operation.  We shouldn't have to call sort
+differently, just because it happens to be generic.
+
+You could pass the list type as a generic actual, but that seems like
+overkill when the operation only has a single parameter.
+
+We also need to affirm the declaration of Ordered_Sets.Generic_Keys.
+
+
+> > Q6) Tucker has mentioned that he often has components in the key of a 
+> >map  beyond the actual key participating ones. (This is similar to the  
+...
+> I think this is a case of "Don't do that!"
+> 
+> Isn't the basic idea that key values are there specifically 
+> to provide fast indexed access to the elements? I don't think 
+> they are not intended to be used to carry ancillary information.
+
+
+Well, that's the debate.  We can use either model, but we have to chose one.
+
+Essentially, the API as it stands now has not been designed to facilitate
+replacement of key values.  The problem is that to support key modification,
+there will most likely be some kind of penality, either static (more complex
+interface) or dynamic (less efficient execution).  The decision is whether
+the added generality is worth the penalty.
+
+
+> > Q4) Set_Capacity is defined to raise Constraint_Error if  Length 
+> >(Container) > Count. Matt would prefer that this case is not  
+> >separately handled. He would like
+> >    Set_Capacity (M, 0)
+> >to be a shorthand for setting the Map or Vector to the smallest  
+> >reasonable size. (I find this a bit odd, as Matt never wanted this  
+> >routine to even allow smaller values. But whatever.) Note that just  
+> >dropping the check would not be enough; we'd have to redo the 
+> >description  of the operation to say that the capacity is set to at 
+> >least  Count_Type'Max (Count, Length(Container)) -- because we don't 
+> >want this  operation to drop elements. I'm unsure that the benefit is 
+> >worth the  change, and it seems like a bug to me to try to set the 
+> >capacity of a  container to be smaller than the number of elements it 
+> >holds.
+> 
+> I think this is a case where readability is more important 
+> than conciseness of code, and I think using an explicit 
+> length will usually be more readable. At least, I think its 
+> meaning is a bit more intuitively obvious.
+
+The meaning of an operation is its postcondition.  (See Meyer's description
+of Hoare triples in OOSC, read David Gries' book, and read EWD's books and
+technical notes.  For more information about the proper use of exceptions,
+see the paper at Barne Stroustrup's home page, or just read Appendix E of
+TC++PL.)
+
+The postcondition of Set_Capacity is:
+
+  Capacity(V) >= Capacity
+
+A vector (or hashed map) also satisfies the invariant that:
+
+  Capacity(V) >= Length(V)
+
+Set_Capacity does whatever is necessary to satisfy both of these predicates.
+Whether the requested capacity is less than the current length is
+irrelevant, since the representation invariant already handles that case.
+
+An exception would only be proper if Set_Capacity were unable to satisfy the
+postcondition or the invariant.
+
+
+> ~~~
+> 
+> Q5 was about using an extra parameter of an enumerated type 
+> in insertion and replacement procedures to indicate what 
+> should happen if the key exists
+> (insertion) or doesn't exist (replacement), with a default 
+> indicating that an exception should be raised.
+> 
+> I rather prefer this idea. I think it is the least of three 
+> evils (no user choice, a plethora of procedures, or control-coupling).
+
+
+I have already stated that I am not in favor of this change.  (It's at the
+wrong level of abstraction, for one thing.)
+
+> ~~~
+> 
+> Another question that arises in my mind is, for any of the 
+> functions which returns a container: what is the capacity of 
+> the result? In particular, should this be defined by the 
+> standard, or remain implementation defined? [Call this Q7?]
+
+
+All this standard says is that Capacity(C) >= Length(C).  If you want more
+control of the capacity, then use the procedures, not the functions.
+
+****************************************************************
+
+From: Nick Roberts
+Sent: Tuesday, September 14, 2004 10:06 AM
+
+Matthew Heaney wrote:
+
+>>The problem with Last_Index (Container) + 1 is that it may 
+>>not exist, because Last_Index (Container) might be 
+>>Index_Type'Last. 
+> 
+> But Find_Index returns Index_Type'Base.  There's an implied requirement that
+> Last_Index(V) < Index_Type'Base'Last, so it doesn't matther if Last_Index(V)
+> = Index_Type'Last.
+
+If there is such a requirement, it should be explicit. But I would be 
+alarmed if such a requirement really was imposed: it would be a classic 
+potential source of obscure bugs.
+
+> Remember the purpose of a vector is to expand.  That's what influenced our
+> decision to use an integer type as the index instead of any discrete type.
+> Your argument that Last_Index(V) might equal Index_Type'Last is tantamount
+> to saying that an enumeration type should be able to be used as the index
+> type, but this matter has already been debated and settled.
+
+I don't think so at all (that Last_Index(V) might equal Index_Type'Last is 
+  tantamount to saying that an enumeration type should be able to be used 
+as the index type). On an implementation that has an 16-bit Integer'Base 
+type, and where V is of a package instantiated with Index_Type Positive, it 
+is quite feasible that Last_Index(V) becomes 32767.
+
+> Allowing an Index_Type to be passed as a generic formal is really only
+> intended to allow the user to specify the starting point of the index
+> subtype range.  The ending point should be large relative to the number of
+> elements typically stored in the container.  
+
+Why? Why should it (Index_Type'Last) not be equal to the maximum number of 
+elements to be stored? It would be prudent to be sure that the maximum was 
+never exceeded, in such a case.
+
+Let me give you an example. Supposing we are programming a card game, and 
+we need a container that can contain a 'hand', which is a list of cards. 
+The rules of this game do not limit the number of cards in a hand, as such, 
+but since the cards come from a pack of 52, we can be absolutely certain 
+that the limit of 52 will never be exceeded. It would therefore be quite 
+reasonable (wouldn't it?) to write:
+
+    type Card_Count is range 0..52;
+    subtype Card_Index is Card_in_Hand_Count range 1..52;
+    package Hand_Vectors is
+       new Ada.Containers.Vectors (Card_ID, Card_Index);
+    ...
+    Dealer: Hand_Vectors.Vector := Random_52;
+    Hands: array (Player_ID) of Hand_Vectors.Vector;
+
+We could move cards between Dealer and Hands throughout the program, safe 
+in the knowledge that although a length of 52 is possible (certain, for 
+Dealer), that length can never be exceeded.
+
+>>I think it would make much more sense for Generic_Sort to be declared:
+>>[not classwide]
+>>and the typecast to be done in the call instead. For example:
+>>...
+>>    Sort( Float_Lists.List(L1) );
+>>
+>>I prefer this because it makes it explicit that the list L1 
+>>is being sorted /as/ a Float_Lists.List (not as a My_List, as such).
+> 
+> But this argument applies to any operation.  We shouldn't have to call sort
+> differently, just because it happens to be generic.
+
+We have to call Sort differently because it's argument isn't of type 
+Float_Lists.List. This fact applies to any non-inherited operation of List, 
+generic or not. That is my point.
+
+> You could pass the list type as a generic actual, but that seems like
+> overkill when the operation only has a single parameter.
+
+I quite agree, and I'd argue the same for Generic_Merge (which only has two 
+parameters). I'm also saying that making them classwide would be overkill.
+
+> We also need to affirm the declaration of Ordered_Sets.Generic_Keys.
+
+What are the alternatives, please?
+
+>>Isn't the basic idea that key values are there specifically 
+>>to provide fast indexed access to the elements? I don't think 
+>>they are not intended to be used to carry ancillary information.
+> 
+> Well, that's the debate.  We can use either model, but we have to chose one.
+
+Okay.
+
+> Essentially, the API as it stands now has not been designed to facilitate
+> replacement of key values.  The problem is that to support key modification,
+> there will most likely be some kind of penality, either static (more complex
+> interface) or dynamic (less efficient execution).  The decision is whether
+> the added generality is worth the penalty.
+
+I don't think it is. I'm saying that I do indeed think we should stick to 
+the model that key values are only for the purpose of indexing.
+
+>>> [re: Set_Capacity(M,n) where n<Length(M)]
+>>I think this is a case where readability is more important 
+>>than conciseness of code, and I think using an explicit 
+>>length will usually be more readable. At least, I think its 
+>>meaning is a bit more intuitively obvious.
+> 
+> The meaning of an operation is its postcondition.
+
+I'm not arguing about the semantic meaning of the operation, Matt! How can 
+I put it more plainly? I'm saying that this is a matter of readability.
+
+The semantic meanings of your suggested Set_Capacity(M,0) and of 
+Set_Capacity(M,Length(M)) are identical, so this is simply not an issue.
+
+I am arguing that Set_Capacity(M,Length(M)) is more readable, and for that 
+reason we should disallow Set_Capacity(M,0). That is all.
+
+In fact, I would accept the procedure being renamed (again ;-) to 
+Set_Minimum_Capacity with the semantics you suggest. Or possibly declare 
+the procedure as:
+
+    procedure Set_Capacity (Container: in out Vector|List|etc;
+                            Minimum:   in     Count_Type);
+
+so that the call can be made:
+
+    Set_Capacity (M, Minimum => 0);
+
+>>Q5 was about using an extra parameter of an enumerated type 
+>>in insertion and replacement procedures to indicate what 
+>>should happen if the key exists
+>>(insertion) or doesn't exist (replacement), with a default 
+>>indicating that an exception should be raised.
+>>
+>>I rather prefer this idea. I think it is the least of three 
+>>evils (no user choice, a plethora of procedures, or control-coupling).
+> 
+> I have already stated that I am not in favor of this change.  (It's at the
+> wrong level of abstraction, for one thing.)
+
+Okay, but I feel that arguments about the level of abstraction are a bit of 
+a nicety here. Am I wrong that we are faced with three choices, none of 
+which is plainly ideal?
+
+>>Another question that arises in my mind is, for any of the 
+>>functions which returns a container: what is the capacity of 
+>>the result? In particular, should this be defined by the 
+>>standard, or remain implementation defined? [Call this Q7?]
+> 
+> All this standard says is that Capacity(C) >= Length(C).  If you want more
+> control of the capacity, then use the procedures, not the functions.
+
+So, are you saying that the standard /should/ leave it implementation 
+defined what the capacity is?
+
+****************************************************************
+
+From: Matthew Heaney
+Sent: Tuesday, September 14, 2004  1:02 PM
+
+>> But Find_Index returns Index_Type'Base.  There's an implied 
+>> requirement that
+>> Last_Index(V) < Index_Type'Base'Last, so it doesn't matther if 
+>> Last_Index(V)
+>> = Index_Type'Last.
+> 
+> If there is such a requirement, it should be explicit. But I would be 
+> alarmed if such a requirement really was imposed: it would be a classic 
+> potential source of obscure bugs.
+
+Not at all.  If Last_Index(V) = Index_Type'Base'Last, and the element 
+isn't in the vector, then Find will raise Constraint_Error.  Nothing 
+obscure about that...
+
+
+>> Remember the purpose of a vector is to expand.  That's what influenced our
+>> decision to use an integer type as the index instead of any discrete type.
+>> Your argument that Last_Index(V) might equal Index_Type'Last is tantamount
+>> to saying that an enumeration type should be able to be used as the index
+>> type, but this matter has already been debated and settled.
+> 
+> 
+> I don't think so at all (that Last_Index(V) might equal Index_Type'Last 
+> is  tantamount to saying that an enumeration type should be able to be 
+> used as the index type). On an implementation that has an 16-bit 
+> Integer'Base type, and where V is of a package instantiated with 
+> Index_Type Positive, it is quite feasible that Last_Index(V) becomes 32767.
+
+Then you used the wrong index type.  Say this instead:
+
+    type Index_Type is new Count_Type range 1 .. Count_Type'Last;
+
+
+Remember also that Find must perform a linear scan of the vector.  In 
+your vector that's over 32000 elements.  Hmmm... Perhaps you should 
+consider using a different container.
+
+
+>> Allowing an Index_Type to be passed as a generic formal is really only
+>> intended to allow the user to specify the starting point of the index
+>> subtype range.  The ending point should be large relative to the 
+>> number of
+>> elements typically stored in the container.  
+> 
+> 
+> Why? Why should it (Index_Type'Last) not be equal to the maximum number 
+> of elements to be stored? It would be prudent to be sure that the 
+> maximum was never exceeded, in such a case.
+
+But we're not arguing about Index_Type'Last, we're arguing about 
+Index_Type'Base'Last.  If you want to define Index_Type'Last such that 
+it equals the maximum number of elements, then go right ahead.
+
+
+> Let me give you an example. Supposing we are programming a card game, 
+> and we need a container that can contain a 'hand', which is a list of 
+> cards. The rules of this game do not limit the number of cards in a 
+> hand, as such, but since the cards come from a pack of 52, we can be 
+> absolutely certain that the limit of 52 will never be exceeded. It would 
+> therefore be quite reasonable (wouldn't it?) to write:
+> 
+>    type Card_Count is range 0..52;
+>    subtype Card_Index is Card_in_Hand_Count range 1..52;
+>    package Hand_Vectors is
+>       new Ada.Containers.Vectors (Card_ID, Card_Index);
+>    ...
+>    Dealer: Hand_Vectors.Vector := Random_52;
+>    Hands: array (Player_ID) of Hand_Vectors.Vector;
+
+All you need to do to fix this is:
+
+   type Card_Count is range 0..53;
+   subtype Card_Index is Card_in_Hand_Count range 1..52;
+   package Hand_Vectors is
+      new Ada.Containers.Vectors (Card_ID, Card_Index);
+
+and now all is well.
+
+
+> We could move cards between Dealer and Hands throughout the program, 
+> safe in the knowledge that although a length of 52 is possible (certain, 
+> for Dealer), that length can never be exceeded.
+
+Fine.  See above.
+
+
+>>> I think it would make much more sense for Generic_Sort to be declared:
+>>> [not classwide]
+>>> and the typecast to be done in the call instead. For example:
+>>> ...
+>>>    Sort( Float_Lists.List(L1) );
+>>>
+>>> I prefer this because it makes it explicit that the list L1 is being 
+>>> sorted /as/ a Float_Lists.List (not as a My_List, as such).
+>>
+>>
+>> But this argument applies to any operation.  We shouldn't have to call 
+>> sort
+>> differently, just because it happens to be generic.
+> 
+> 
+> We have to call Sort differently because it's argument isn't of type 
+> Float_Lists.List. This fact applies to any non-inherited operation of 
+> List, generic or not. That is my point.
+
+No, we don't have to call it differently.  That's my point.
+
+
+>> You could pass the list type as a generic actual, but that seems like
+>> overkill when the operation only has a single parameter.
+> 
+> 
+> I quite agree, and I'd argue the same for Generic_Merge (which only has 
+> two parameters). I'm also saying that making them classwide would be 
+> overkill.
+
+But we want to *statically* check that both parameters have the same 
+specific type, something we can't do if the parameters have type List'Class.
+
+
+>> We also need to affirm the declaration of Ordered_Sets.Generic_Keys.
+> 
+> 
+> What are the alternatives, please?
+
+Same as for Generic_Sort or Generic_Merge.
+
+
+>>>> [re: Set_Capacity(M,n) where n<Length(M)]
+>>>
+>>> I think this is a case where readability is more important than 
+>>> conciseness of code, and I think using an explicit length will 
+>>> usually be more readable. At least, I think its meaning is a bit more 
+>>> intuitively obvious.
+>>
+>>
+>> The meaning of an operation is its postcondition.
+> 
+> 
+> I'm not arguing about the semantic meaning of the operation, Matt! How 
+> can I put it more plainly? I'm saying that this is a matter of readability.
+
+The problem is that users are probably going to have to check, prior to 
+making the call, in order to avoid raising Constraint_Error.  But this 
+unnecessary check is only crying wolf, since nothing bad happens when 
+Capacity < Length(V).
+
+
+> The semantic meanings of your suggested Set_Capacity(M,0) and of 
+> Set_Capacity(M,Length(M)) are identical, so this is simply not an issue.
+> 
+> I am arguing that Set_Capacity(M,Length(M)) is more readable, and for 
+> that reason we should disallow Set_Capacity(M,0). That is all.
+
+That fact that you don't like this locution is not a compelling reason 
+to disallow it.
+
+This API specifies a postcondition, the operation satisfies the 
+postcondition, and therefore there is no exception.  It's very simple.
+
+Exceptions are not a mechanism for social engineering of software.
+
+
+>>> Q5 was about using an extra parameter of an enumerated type in 
+>>> insertion and replacement procedures to indicate what should happen 
+>>> if the key exists
+>>> (insertion) or doesn't exist (replacement), with a default indicating 
+>>> that an exception should be raised.
+>>>
+>>> I rather prefer this idea. I think it is the least of three evils (no 
+>>> user choice, a plethora of procedures, or control-coupling).
+>>
+>>
+>> I have already stated that I am not in favor of this change.  (It's at the
+>> wrong level of abstraction, for one thing.)
+> 
+> 
+> Okay, but I feel that arguments about the level of abstraction are a bit 
+> of a nicety here. Am I wrong that we are faced with three choices, none 
+> of which is plainly ideal?
+
+The 5-parameter insert is already ideal, since it's completely general. 
+   Any other behavior you want can be written in terms of the canonical 
+insert.
+
+
+>>> Another question that arises in my mind is, for any of the functions 
+>>> which returns a container: what is the capacity of the result? In 
+>>> particular, should this be defined by the standard, or remain 
+>>> implementation defined? [Call this Q7?]
+>>
+>>
+>> All this standard says is that Capacity(C) >= Length(C).  If you want 
+>> more
+>> control of the capacity, then use the procedures, not the functions.
+> 
+> 
+> So, are you saying that the standard /should/ leave it implementation 
+> defined what the capacity is?
+
+Yes, of course.  The standard needs needs to get out of the vendors' 
+way, too.
+
+****************************************************************
+
+From: Nick Roberts
+Sent: Tuesday, September 14, 2004  9:21 PM
+
+Matthew Heaney wrote:
+
+> Not at all.  If Last_Index(V) = Index_Type'Base'Last, and the element 
+> isn't in the vector, then Find will raise Constraint_Error.  Nothing 
+> obscure about that...
+
+Okay, but is that really the behaviour we want?
+
+> Then you used the wrong index type.  Say this instead:
+> 
+>    type Index_Type is new Count_Type range 1 .. Count_Type'Last;
+
+Okay, but I think this point might not be obvious to many programmers.
+
+> Remember also that Find must perform a linear scan of the vector.  In 
+> your vector that's over 32000 elements.  Hmmm... Perhaps you should 
+> consider using a different container.
+
+I think this kind of scan will be appropriate for some applications. The 
+vector might contain over 32000 elements, but the scan might not start at 
+the beginning of the vector. Anyway, I don't think this point is very relevant.
+
+> But we're not arguing about Index_Type'Last, we're arguing about 
+> Index_Type'Base'Last.  If you want to define Index_Type'Last such that 
+> it equals the maximum number of elements, then go right ahead.
+
+But in general, if I declare:
+
+    type T is range A..B;
+
+I cannot know that T'B < T'Base'B.
+
+> All you need to do to fix this is:
+> 
+>   type Card_Count is range 0..53;
+>   subtype Card_Index is Card_in_Hand_Count range 1..52;
+>   package Hand_Vectors is
+>      new Ada.Containers.Vectors (Card_ID, Card_Index);
+> 
+> and now all is well.
+
+Except that Card_Count having a rnage of 0..53 just for the convenience of 
+the Find function is surely poor programming?
+
+Incidentally, I made a boob:
+
+    subtype Card_Index is Card_in_Hand_Count range 1..52;
+
+was meant to be:
+
+    subtype Card_Index is Card_Count range 1..52;
+
+Sorry.
+
+>> We have to call Sort differently because it's argument isn't of type 
+>> Float_Lists.List. This fact applies to any non-inherited operation of 
+>> List, generic or not. That is my point.
+> 
+> No, we don't have to call it differently.  That's my point.
+
+I'm pretty sure that we do. For example, if I declare:
+
+    package Thing_Vectors is Ada.Containers.Vectors(Thing,Positive);
+    package Sort is new Thing_Vectors.Generic_Sort; -- non-inherited op
+    ...
+    procedure Foo (Them: in out Thing_Vectors.Vector); -- non-inherited op
+    ...
+    type Other_Vector is new Thing_Vectors.Vector;
+    ...
+    V2: Other_Vector;
+    ...
+    Sort (Thing_Vectors.Vector(V2));
+    Foo  (Thing_Vectors.Vector(V2));
+
+we must typecast V2 for the calls to both Sort and Foo, because they are 
+both non-inherited operations (and not specially declared for Other_Vector).
+
+>> I quite agree, and I'd argue the same for Generic_Merge (which only 
+>> has two parameters). I'm also saying that making them classwide would 
+>> be overkill.
+> 
+> But we want to *statically* check that both parameters have the same 
+> specific type, something we can't do if the parameters have type 
+> List'Class.
+
+You've got hold of the wrong end of the stick, Matt! I am saying myself 
+that the parameters to both Generic_Sort and Generic_Merge should /not/ be 
+classwide. I am agreeing with you! I /agree/ that we want to statically 
+check that both parameters (to any call of any instantiation of 
+Generic_Merge) are of the same type.
+
+I was saying that I think Generic_Sort should not have a classwide 
+parameter, because it would be better style for derived types (derived from 
+Vector or List) to be explicitly typecast in a call to an instantiation of 
+Generic_Sort, than to be opaquely typecast within the implementation.
+
+>>> We also need to affirm the declaration of Ordered_Sets.Generic_Keys.
+>>
+>> What are the alternatives, please?
+> 
+> Same as for Generic_Sort or Generic_Merge.
+
+I don't quite understand this, since Generic_Sort and Generic_Merge are 
+generic procedures, and Ordered_Sets.Generic_Keys is a generic package.
+
+However, if you're suggesting that parameters of type Set in this package 
+be made classwide (Set'Class), I would prefer not, for similar reasons as 
+above.
+
+> That fact that you don't like this locution is not a compelling reason 
+> to disallow it.
+
+I wasn't trying to argue that it is a /compelling/ reason, only that it is 
+a reason.
+
+Anyway, what do you think of the idea of changing the name of Set_Capacity 
+to Set_Minimum_Capacity, or its Capacity parameter to Minimum?
+
+>> Okay, but I feel that arguments about the level of abstraction are a 
+>> bit of a nicety here. Am I wrong that we are faced with three choices, 
+>> none of which is plainly ideal?
+> 
+> The 5-parameter insert is already ideal, since it's completely general. 
+>   Any other behavior you want can be written in terms of the canonical 
+> insert.
+
+Fair enough. I still think the suggested versions of Insert (with an 
+If_Exists parameter) and Replace (with an If_Nonexistent parameter) should 
+be added, on the grounds of significant convenience.
+
+>> So, are you saying that the standard /should/ leave it implementation 
+>> defined what the capacity is?
+> 
+> Yes, of course.  The standard needs needs to get out of the vendors' 
+> way, too.
+
+Yes, I agree with this.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Tuesday, September 14, 2004  9:40 PM
+
+...
+> we must typecast V2 for the calls to both Sort and Foo, because they are
+> both non-inherited operations (and not specially declared for
+> Other_Vector).
+
+You never have to use a type conversion to call a routine with a class-wide
+parameter of a root class, which is the case here.
+
+Our "standard" for Claw was that a specific typed non-primitive parameter
+represented a bug, as it would just restrict the uses of the library for no
+benefit. We in fact wrote checking for that into our help file generator,
+and later removed most of the ones found. (There were a couple of cases
+where extensions would have been real problems, functions that returned
+objects or for procedures with 'out' parameters. Neither applies to
+Generic_Sort.)
+
+The same appears to be true for the Containers libraries.
+
+****************************************************************
+
+From: Matthew Heaney
+Sent: Wednesday, September 15, 2004  2:28 AM
+
+> > But we're not arguing about Index_Type'Last, we're arguing about
+> > Index_Type'Base'Last.  If you want to define Index_Type'Last such that 
+> > it equals the maximum number of elements, then go right ahead.
+> 
+> But in general, if I declare:
+> 
+>     type T is range A..B;
+> 
+> I cannot know that T'B < T'Base'B.
+
+That's because you declared T incorrectly:
+
+   type T_Base is A .. B + 1;
+   type T is new T_Base range A .. B;
+ 
+> > All you need to do to fix this is:
+> > 
+> >   type Card_Count is range 0..53;
+> >   subtype Card_Index is Card_in_Hand_Count range 1..52;
+> >   package Hand_Vectors is
+> >      new Ada.Containers.Vectors (Card_ID, Card_Index);
+> > 
+> > and now all is well.
+> 
+> Except that Card_Count having a rnage of 0..53 just for the convenience of 
+> the Find function is surely poor programming?
+
+This simply reflects Ada95 idioms for type declarations.  You have to
+declare a pseudo base type whose (base) range has the range required, and
+then declare the real type as a subtype or derived type that restricts the
+range.  See the "sum of 3 numbers" thread on CLA from a few months ago.
+
+> >>> We also need to affirm the declaration of Ordered_Sets.Generic_Keys.
+> >>
+> >> What are the alternatives, please?
+> > 
+> > Same as for Generic_Sort or Generic_Merge.
+> 
+> I don't quite understand this, since Generic_Sort and Generic_Merge are 
+> generic procedures, and Ordered_Sets.Generic_Keys is a generic package.
+> 
+> However, if you're suggesting that parameters of type Set in this package 
+> be made classwide (Set'Class), I would prefer not, for similar reasons as 
+> above.
+
+I'm leaning myself towards importing the set type as a generic formal.
+We'll have to see how the ARG weighs in this weekend.
+
+> Anyway, what do you think of the idea of changing the name of Set_Capacity 
+> to Set_Minimum_Capacity, or its Capacity parameter to Minimum?
+
+Too much verbosity.  (That's the same reason I'm not crazy about the name
+"Insert_Or_Replace".)
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Wednesday, September 15, 2004  6:19 PM
+
+...
+> > Our "standard" for Claw was that a specific typed non-primitive parameter
+> > represented a bug, as it would just restrict the uses of the library for no
+> > benefit.
+> 
+> But it wouldn't actually /retrict/ uses of the subprogram, would it? It 
+> would simply mean that the user would have to write an explicit type 
+> conversion for an object or expression of a derived type, wouldn't it?
+
+Writing unnecessary type conversions *is* a bug. The reason for wanting explicit
+type is to indicate the possibility of a problem (for conversions that can fail or
+lose precision). Neither is true here. It's the same reason that Ada 05 expands the
+use of anonymous access types -- if you have conversions that can't fail, they're not
+interesting conversions -- they just clutter the code.
+
+> On the other hand, doesn't making the parameter class-wide restrict new 
+> overloadings of the subprogram (for a derived type)? I think that could be 
+> quite inconvenient occasionally.
+
+"Occasionally", perhaps. If you use a ton of use clauses. Otherwise, it's a
+non-problem, because the new routine would necessarily be in a different package.
+
+>  > We in fact wrote checking for that into our help file generator,
+> > and later removed most of the ones found. (There were a couple of cases
+> > where extensions would have been real problems, functions that returned
+> > objects or for procedures with 'out' parameters. Neither applies to
+> > Generic_Sort.)
+> 
+> I think this is the kind of problem I'm worried about. For a container type 
+> T1, Generic_Sort may be instantiated to a procedure named Sort (or 
+> whatever) in one phase of software construction, which may then get frozen, 
+> and then a type T2 may be derived from T1 in a later phase. It might be an 
+> annoyance not to be able to declare a new overloaded Sort (or whatever) for 
+> T2. I suppose you'd have to name it something like Sort_T2. Not a disaster, 
+> but an annoyance. (Of course, you /could/ declare the overloaded Sort, but 
+> you couldn't call it unambiguously.)
+
+No problem, just prefix it to call it unambiguously. Moreover, if the Sort is
+class-wide, you don't even need to do this new routine; just call the original
+one. (If the instantiation is in the package with the type declaration, you can
+even do that with the prefix notation without any extra with or use clauses.)
+
+> > The same appears to be true for the Containers libraries.
+> 
+> It does seem to be a similar situation. I have often found difficulty in 
+> deciding on these kinds of details of the design, for packages which export 
+> tagged types. I generally find that it's a mistake to try to be 
+> too 'clever'.
+
+I agree. My rule is that all operations are either primitive or class-wide unless
+they are creating a new object of the type.
+
+> A class-wide parameter implies a dispatching implementation, doesn't it? 
+
+No, not to me. It implies an operation that is *meaningful* to all members of a type.
+How it's implemented is not relevant.
+
+> However, the implementation of Generic_Sort would not do any dispatching; 
+> it would simply have to internally typecast the parameter to the root type.
+
+That would be open to debate. It certainly would be easier to define it this way,
+but it would make sense for it to dispatch to the primitive operations of the type.
+(But that probably would be a mistake for performance reasons.)
+ 
+> I feel that this fact indicates a bug. I think, for this reason, it would 
+> not be the right design to make the parameter(s) class-wide for 
+> Generic_Sort or for Generic_Merge.
+
+Nope, it's irrelevant in my view. Claw has an entire package of operations on
+Root_Window_Type'Class, and there isn't a single dispatching operation in the bunch.
+They are all operations that make sense on any window; the implementation ought to
+be irrelevant.
+
+****************************************************************
+
+From: Robert A. Duff
+Sent: Wednesday, September 15, 2004  6:55 AM
+
+> That's because you declared T incorrectly:
+> 
+>    type T_Base is A .. B + 1;
+>    type T is new T_Base range A .. B;
+
+I think you want:
+
+    subtype T is T_Base range A .. B;
+
+****************************************************************From: Nick Roberts
+Sent: Wednesday, September 15, 2004  9:19 AM
+
+>>But in general, if I declare:
+>>
+>>    type T is range A..B;
+>>
+>>I cannot know that T'B < T'Base'B.
+> 
+> That's because you declared T incorrectly:
+> 
+>    type T_Base is A .. B + 1;
+>    type T is new T_Base range A .. B;
+
+True, but it might not be obvious to a user that this must be done for an 
+instantiation of Ada.Containers.Vectors.
+
+> This simply reflects Ada95 idioms for type declarations.  You have to
+> declare a pseudo base type whose (base) range has the range required, and
+> then declare the real type as a subtype or derived type that restricts the
+> range.  See the "sum of 3 numbers" thread on CLA from a few months ago.
+
+Yes, you are quite right.
+
+However, does this suggest that we need to add a second assertion?
+
+    pragma Assert (Index_Type'Last < Index_Type'Base'Last);
+
+I don't really see why we don't just return Index_Type'First-1; it's what 
+the string packages do.
+
+> I'm leaning myself towards importing the set type as a generic formal.
+> We'll have to see how the ARG weighs in this weekend.
+
+I think I see the logic of this idea, but I feel there is a danger that it 
+might be a bit confusing for some users.
+
+>>Anyway, what do you think of the idea of changing the name of 
+>>Set_Capacity 
+>>to Set_Minimum_Capacity, or its Capacity parameter to Minimum?
+> 
+> Too much verbosity.  (That's the same reason I'm not crazy about the name
+> "Insert_Or_Replace".)
+
+Okay, but isn't verbosity a lesser sin than the potential for 
+misinterpretation? Up to a point, certainly. I'm not suggesting a name such 
+as Set_Capacity_to_This_Unless_It_Is_Less_Than_The_Length_In_Which_Case_...
+
+Anyway, changing the parameter name from 'Capacity' to 'Minimum' isn't 
+increasing the verbosity (it would actually reduce it by one letter :-)
+
+****************************************************************
+
+From: Matthew Heaney
+Sent: Wednesday, September 15, 2004  9:28 AM
+
+Randy wrote:
+
+>> Q1) Find_Index returns Last_Index (Container) + 1 if the element is not
+>> found. This seems consistent to me (it's past the end of the container in
+>> a forward search), but Matt worries that First_Index (Container) - 1
+>> might be thought of as better. The trouble with First_Index (Container) -
+>> 1 is that you can't put it into an object:
+>>    declare
+>>         I : Index_Type := Index_Type'First;
+>>     begin
+>>         I := Find_Index (Vect, Item, I);
+>>         while I <= Last_Index (Vect) loop
+>>             -- Do something to the element I.
+>>             I := Find_Index (Vect, Item, I+1);
+>>         end loop;
+>>     end;
+>> If Find_Index returned Index_Type'First - 1, saving the result of
+>> Find_Index would raise Constraint_Error if the item is not found. That's
+>> not what we want, I think.
+
+Actually, I think this example is wrong anyway.  Object I should have 
+type Index_Type'Base.  You could write instead (see below):
+
+    declare
+         I : Index_Type'Base := Find_Index (Vect, Item);
+     begin
+         while I /= No_Index loop
+             -- Do something to the element I.
+             I := Find_Index (Vect, Item, I+1);
+         end loop;
+     end;
+
+One issue with Randy's original formulation is that there's a constraint 
+check every time object I is assigned the value returned by Find.
+
+We could always liberalize what is acceptable as the value of the Index 
+parameter of Find.  Right now, we raise CE if Index < Index_Type'First, 
+but it might make sense to allow No_Index (actually, any value less then 
+Index_Type'First) as the value, and interpret that to mean begin the 
+search at Index_Type'First.
+
+
+Nick Roberts responded:
+
+> The problem with Last_Index (Container) + 1 is that it may not exist,
+> because Last_Index (Container) might be Index_Type'Last. On the other hand,
+> we convenienty have a requirement that Index_Type'First >
+> Index_Type'Base'First, which guarantees that First_Index (Container) - 1
+> does always exist (as a value of Index_Type'Base).
+> 
+> I think that swings it. I suggest Find_Index returns First_Index
+> (Container) - 1 when it does not find what it is looking for.
+...
+
+This is actually closer to how std::string works.  If a search fails, it 
+returns std::string::npos, which is defined as string::size_type(-1).
+
+It would be similar to what you have above:
+
+    No_Index : constant Index_Type'Base :=
+       Index_Type'Pred (Index_Type'First);
+
+
+We would then have to affirm whether To_Index should raise CE if given 
+No_Element as the argument, or return the value No_Index instead.  (Our 
+original motivation for raising CE was that we didn't know what index 
+value to return, but if we declare No_Index as a distinguished value, 
+then we really do have a value to return that makes sense.)
+
+****************************************************************
+
+From: Matthew Heaney
+Sent: Wednesday, September 15, 2004  9:31 AM
+
+> However, does this suggest that we need to add a second assertion?
+> 
+>    pragma Assert (Index_Type'Last < Index_Type'Base'Last);
+> 
+> I don't really see why we don't just return Index_Type'First-1; it's 
+> what the string packages do.
+
+I would be in favor of declaring an object of type Index_Type'Base, 
+named No_Index (or whatever), whose value is Index_Type'First - 1. 
+Find_Index and Reverse_Find_Index would return No_Index when the search 
+fails.
+
+I would also be in favor of function To_Index returning No_Index when 
+the parameter has the cursor value No_Element (instead of raising CE).
+
+See my previous post for the details.
+
+Note that you can't write that assertion, because it would fail for 
+generic actual types like Natural or Positive.
+
+****************************************************************
+
+From: Nick Roberts
+Sent: Wednesday, September 15, 2004  5:25 PM
+
+ > I would be in favor of declaring an object of type Index_Type'Base,
+ > named No_Index (or whatever), whose value is Index_Type'First - 1.
+ > Find_Index and Reverse_Find_Index would return No_Index when the search
+ > fails.
+
+Specifically, I suggest the following declaration is inserted into the
+Ada.Containers.Vectors package specification:
+
+    No_Index: constant Index_Type'Base := Index_Type'First - 1;
+
+ > I would also be in favor of function To_Index returning No_Index when
+ > the parameter has the cursor value No_Element (instead of raising CE).
+ >
+ > See my previous post for the details.
+
+I suggest the wording for To_Index in this package is changed to:
+
+    function To_Index (Position : Cursor) return Index_Type'Base;
+
+    If Position is No_Element, To_Index returns No_Index. Otherwise, it
+    returns the index (within its containing vector) of the element
+    designated by Cursor.
+
+I suggest the wording for the Find_Index and Reverse_Find_Index functions
+is changed to:
+
+    function Find_Index (Container : Vector;
+                         Item      : Element_Type;
+                         Index     : Index_Type'Base := Index_Type'First)
+       return Index_Type'Base;
+
+    Searches the elements of Container for an element equal to Item,
+    starting at position Index. If Index is less than Index_Type'First, then
+    the search begins at Index_Type'First. If there are no elements in the
+    range Index .. Last_Index (Container) equal to Item, then Find_Index
+    returns No_Index. Otherwise, it returns the index of the matching
+    element with the lowest index.
+
+    function Reverse_Find_Index (Container : Vector;
+                                 Item      : Element_Type;
+                                 Index : Index_Type'Base := Index_Type'Last)
+       return Index_Type'Base;
+
+    Searches the elements of Container in reverse for an element equal to
+    Item, starting at position Index. If Index is greater than Last_Index
+    (Container), then the search begins at position Last_Index (Container).
+    If there are no elements in the range Index_Type'First .. Index equal to
+    Item, then Reverse_Find_Index returns No_Index. Otherwise, it returns
+    the index of the matching element with the highest index.
+
+I've also added the wording "with the lowest index" and "with the highest
+index" in this suggestion, in the hope it increases clarity slightly.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Wednesday, September 15, 2004  6:19 PM
+
+...
+> > Our "standard" for Claw was that a specific typed non-primitive parameter
+> > represented a bug, as it would just restrict the uses of the library for no
+> > benefit.
+>
+> But it wouldn't actually /retrict/ uses of the subprogram, would it? It
+> would simply mean that the user would have to write an explicit type
+> conversion for an object or expression of a derived type, wouldn't it?
+
+Writing unnecessary type conversions *is* a bug. The reason for wanting
+explicit type is to indicate the possibility of a problem (for conversions
+that can fail or lose precision). Neither is true here. It's the same reason
+that Ada 05 expands the use of  anonymous access types -- if you have
+conversions that can't fail, they're not interesting conversions -- they
+just clutter the code.
+
+> On the other hand, doesn't making the parameter class-wide restrict new
+> overloadings of the subprogram (for a derived type)? I think that could be
+> quite inconvenient occasionally.
+
+"Occasionally", perhaps. If you use a ton of use clauses. Otherwise, it's a
+non-problem, because the new routine would necessarily be in a different
+package.
+
+>  > We in fact wrote checking for that into our help file generator,
+> > and later removed most of the ones found. (There were a couple of cases
+> > where extensions would have been real problems, functions that returned
+> > objects or for procedures with 'out' parameters. Neither applies to
+> > Generic_Sort.)
+>
+> I think this is the kind of problem I'm worried about. For a container type
+> T1, Generic_Sort may be instantiated to a procedure named Sort (or
+> whatever) in one phase of software construction, which may then get frozen,
+> and then a type T2 may be derived from T1 in a later phase. It might be an
+> annoyance not to be able to declare a new overloaded Sort (or whatever) for
+> T2. I suppose you'd have to name it something like Sort_T2. Not a disaster,
+> but an annoyance. (Of course, you /could/ declare the overloaded Sort, but
+> you couldn't call it unambiguously.)
+
+No problem, just prefix it to call it unambiguously. Moreover, if the Sort
+is class-wide, you don't even need to do this new routine; just call the
+original one. (If the instantiation is in the package with the type
+declaration, you can even do that with the prefix notation without any extra
+with or use clauses.)
+
+> > The same appears to be true for the Containers libraries.
+>
+> It does seem to be a similar situation. I have often found difficulty in
+> deciding on these kinds of details of the design, for packages which export
+> tagged types. I generally find that it's a mistake to try to be
+> too 'clever'.
+
+I agree. My rule is that all operations are either primitive or class-wide
+unless they are creating a new object of the type.
+
+> A class-wide parameter implies a dispatching implementation, doesn't it?
+
+No, not to me. It implies an operation that is *meaningful* to all members
+of a type. How it's implemented is not relevant.
+
+> However, the implementation of Generic_Sort would not do any dispatching;
+> it would simply have to internally typecast the parameter to the root type.
+
+That would be open to debate. It certainly would be easier to define it this
+way, but it would make sense for it to dispatch to the primitive operations
+of the type. (But that probably would be a mistake for performance reasons.)
+
+> I feel that this fact indicates a bug. I think, for this reason, it would
+> not be the right design to make the parameter(s) class-wide for
+> Generic_Sort or for Generic_Merge.
+
+Nope, it's irrelevant in my view. Claw has an entire package of operations
+on Root_Window_Type'Class, and there isn't a single dispatching operation in
+the bunch. They are all operations that make sense on any window; the
+implementation ought to be irrelevant.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Wednesday, September 15, 2004  7:01 PM
+
+> I would be in favor of declaring an object of type Index_Type'Base, 
+> named No_Index (or whatever), whose value is Index_Type'First - 1. 
+> Find_Index and Reverse_Find_Index would return No_Index when the search 
+> fails.
+
+That would OK, except that you are assuming that users will somehow magically use
+Index_Type'Base when using Find, but use Index_Type for everything else. That's very
+impractical; I often will put the result of operations like Find directly into the
+resulting data structure (sometimes in an aggregate), and it would be awful to have
+to use 'Base all over. Moreover, how would anyone remember to use 'Base? I don't think
+I've ever written 'Base outside of a generic unit; it certainly wouldn't be the first
+thing I'd think of.
+
+So I view this proposal as being the same as saying that Find raises Constraint_Error
+whenever the object is not found. Moreover, this isn't documented, so most users will
+have to find it out by trial and error. Unless they use the container very frequently,
+this will be a major gotcha.
+ 
+> I would also be in favor of function To_Index returning No_Index when 
+> the parameter has the cursor value No_Element (instead of raising CE).
+
+That means that we have to carefully study every operation to see if the behavior for
+No_Index is proper. Since most of the cursor operations are defined in terms of
+To_Index, that is going to be a big job. (And most likely, some of the index
+operations should *not* raise an exception if given No_Index - Find_Index for
+example.)
+
+While I'm sure we can come up with a consistent semantics, such a major rewrite will
+most likely prevent the AI from being approved at this meeting. (I will be completely
+opposed to approving any AIs with major changes; most of the ones approved in the past
+were too full of holes to complete.)
+
+You'd also be giving more ammunition to those who claim that this container library
+isn't mature enough to standardize. Even though this is arguably a corner-case, it
+gives the impression of continuing flux in the interface.
+
+So, all in all, I'd rather leave the whole thing alone; it's insufficiently broken --
+the only problem is that a failed Find would raise Constraint_Error if the array is
+full. That isn't a major issue - I could argue that failed Find always should raise
+an exception (that's what Claw does in most cases) - and in any case, lots of
+operations are going to fail with a full array. Don't do it. :-)
+
+****************************************************************
+
+From: Matthew Heaney
+Sent: Wednesday, September 15, 2004  11:25 PM
+
+> > I would be in favor of declaring an object of type Index_Type'Base, 
+> > named No_Index (or whatever), whose value is Index_Type'First - 1. 
+> > Find_Index and Reverse_Find_Index would return No_Index when the 
+> > search fails.
+> 
+> That would OK, except that you are assuming that users will 
+> somehow magically use Index_Type'Base when using Find, but 
+> use Index_Type for everything else. That's very impractical; 
+> I often will put the result of operations like Find directly 
+> into the resulting data structure (sometimes in an 
+> aggregate), and it would be awful to have to use 'Base all 
+> over. Moreover, how would anyone remember to use 'Base? I 
+> don't think I've ever written 'Base outside of a generic 
+> unit; it certainly wouldn't be the first thing I'd think of.
+
+This is the most compelling argument (for retaining the current semantics).
+I often assume most Ada users are like Bob Duff, and sometimes need
+reminding that there are very few Bob Duffs...
+
+
+> So I view this proposal as being the same as saying that Find 
+> raises Constraint_Error whenever the object is not found. 
+> Moreover, this isn't documented, so most users will have to 
+> find it out by trial and error. Unless they use the container 
+> very frequently, this will be a major gotcha.
+
+Agreed.
+
+...
+> So, all in all, I'd rather leave the whole thing alone; it's 
+> insufficiently broken -- the only problem is that a failed 
+> Find would raise Constraint_Error if the array is full. That 
+> isn't a major issue - I could argue that failed Find always 
+> should raise an exception (that's what Claw does in most 
+> cases) - and in any case, lots of operations are going to 
+> fail with a full array. Don't do it. :-)
+
+Agreed.
+
+****************************************************************
+
+From: Robert A. Duff
+Sent: Thursday, September 16, 2004  10:27 AM
+
+> This is the most compelling argument (for retaining the current semantics).
+> I often assume most Ada users are like Bob Duff, and sometimes need
+> reminding that there are very few Bob Duffs...
+
+Well, Bob Duff doesn't want to use 'Base all over the place, either.
+
+It seems to me that if there's a "special" value returned in the "not
+found" case, it is entirely Good and Right to declare a constant called
+Not_Found or some such.  And there should be a subtype that includes
+that value plus all the normal index values.  Whether you're putting the
+result of Find functions in data strucutures or local variables, you
+should use that subtype if the result might be Not_Found -- or you can
+assert that it *will* be found by using the normal index subtype.
+
+None of this requires using 'Base "all over" -- perhaps once in the
+generic, and none in client code.
+
+I don't think this is some sort of bobduffian arcanity -- it's no
+different from declaring a subtype 0..N to count the number if Things,
+and another subtype 1..N to index them.
+
+Aside: this is the same reason why Ada desperately needs a "not null"
+constraint on access subtypes.  Otherwise, there's no way to express the
+difference between "X points at a Thing" versus "X either points at a
+Thing or has a special null value".  This is the source of numerous
+bugs, IME.
+
+****************************************************************
+
+From: Matthew Heaney
+Sent: Thursday, September 16, 2004  12:21 PM
+
+The function Last_Index returns Index_Type'Base too, to handle the case 
+of an empty vector.  Indeed, handling the result of Last_Index was the 
+reason we settled on an integer index type.  You could argue for 
+declaring a No_Index value on the basis of Last_Index alone.
+
+Note also that Get_Line returns Line'First - 1 (or is it 0?) when the 
+line is empty.  And Nick has pointed out that the search functions in 
+Ada.Strings.* return 0 to indicate not found.
+
+So there is precedent for needing to handle a "special" value for 
+index-based functions.
+
+We already have an Index_Subtype in the spec, that simply renames the 
+generic formal type.  One way to avoid having to say IT'Base is to 
+define that subtype as:
+
+    subtype Index_Subtype is Index_Type'Base
+       range Index_Type'First - 1 .. Index_Type'Last;
+
+    No_Index : constant Index_Subtype := Index_Subtype'First;
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Thursday, September 16, 2004  1:15 PM
+
+It would need a different name if you were to do that; "Index_Subtype"
+doesn't imply the correct semantics (it implies a constraint, not the lack
+of one). Moreover, as Bob points out, you really need both, and it would
+seem weird to define only one or the other. We usually name these subtypes
+<something>_Count and <something>_Index (or <something>_Indices); the first
+because of the strong precident in Streams, Storage_Elements, and Direct_IO,
+and the second to make it clear what the purpose is. (Direct_IO uses
+"Positive_Count", which is more  confusing than anything.)
+
+The problem with that naming is that we already have a separate type for
+Counts. So I can't think of an appropriate name.
+
+And, in any case, my concerns about making a significant change here still
+apply. This is such a minor issue that it just doesn't seem worth the effort
+of checking and possibly changing the definition of every routine in the
+vector package.
+
+****************************************************************
+
+From: Nick Roberts
+Sent: Thursday, September 16, 2004  5:51 PM
+
+> The problem with that naming is that we already have a separate type for
+> Counts. So I can't think of an appropriate name.
+
+I suggest:
+
+    subtype Index_Subtype is Index_Type;
+
+    subtype Extended_Index is
+       Index_Type'Base range Index_Type'First - 1 .. Index_Type'Last;
+
+    No_Index: constant Extended_Index := Index_Type'First - 1;
+
+    function To_Index (Position  : Cursor) return Extended_Index;
+
+    function Last_Index (Container : Vector) return Extended_Index;
+
+    function Find_Index (Container : Vector;
+                         Item      : Element_Type;
+                         Index     : Index_Type'Base := Index_Type'First)
+       return Extended_Index;
+
+    function Reverse_Find_Index (Container : Vector;
+                                 Item      : Element_Type;
+                                 Index : Index_Type'Base := Index_Type'Last)
+       return Extended_Index;
+
+and change the wording for To_Index and Last_Index to:
+
+    function To_Index (Position  : Cursor) return Extended_Index;
+
+    If Position is No_Element, To_Index returns No_Index. Otherwise, it
+    returns the index (within its containing vector) of the element
+    designated by Cursor.
+
+    function Last_Index (Container : Vector) return Extended_Index;
+
+    If Container is empty, Last_Index returns No_Index; otherwise, it
+    returns the position of the last element in Container.
+
+Some other wordings may need to be changed:
+
+Except for the wording of To_Cursor, change every occurrance of "If Index
+is not in the range First_Index (Container) .. Last_Index (Container)" or
+"If Index does not specify a value in the range First_Index (Container) ..
+Last_Index (Container)" to "If Container is empty or Index is not in the
+range First_Index (Container) .. Last_Index (Container)".
+
+The wording for the To_Cursor function appears to work without change.
+
+The wordings for all the Insert and Insert_Space procedures appear to work
+without change (as a side-benefit of No_Index = Index_Type'First - 1).
+
+Incidentally, the wordings for the Insert and Insert_Space procedures which
+have a Position out-parameter appear to suggest that Position is not set to 
+anything if Length (New_Item) = 0. Is this correct?
+
+The definitions of Append all appear to work without change. Likewise for 
+Delete, Delete_First, and Delete_Last. (The wording for Delete_Last does 
+actually work.)
+
+As a very minor point, the wording for the Delete procedure (with Count)
+has "Any exceptions raised during element assignment are propagated."
+Should this be "Any exception propagated by an element assignment is
+propagated by Delete."?
+
+Also add the wording (after the package spec):
+
+    No_Index represents a position that does not correspond to any element.
+    The subtype Extended_Index covers the indices covered by Index_Subtype
+    plus the value No_Index.
+
+I've already suggested wordings for Find_Index and Reverse_Find_Index.
+
+I don't think anything else is affected.
+
+It seems quite neat to me, in a way, that the declaration of
+Extended_Subtype would supplant the assertion (pragma), as it would itself
+cause any instantiation of Ada.Containers.Vectors with Index_Type'First =
+Index_Type'Base'First to fail.
+
+> And, in any case, my concerns about making a significant change here still
+> apply. This is such a minor issue that it just doesn't seem worth the effort
+> of checking and possibly changing the definition of every routine in the
+> vector package.
+
+For what it's worth, I would like to see these changes made. I don't feel
+that it would be a major change, and I do feel it would be worth it. But I
+guess things are getting close to the bone now.
+
+****************************************************************
+
+From: Matthew Heaney
+Sent: Friday, July 2, 2004  9:31 AM
+
+****************************************************************
+
+From: Matthew Heaney
 Sent: Friday, July 2, 2004  9:31 AM
 
 ****************************************************************

Questions? Ask the ACAA Technical Agent