Version 1.7 of ai05s/ai05-0069-1.txt

Unformatted version of ai05s/ai05-0069-1.txt version 1.7
Other versions for file ai05s/ai05-0069-1.txt

!standard A.18.17(0)          09-03-23 AI05-0069-1/04
!class Amendment 07-10-24
!status Amendment 201Z 08-11-26
!status ARG Approved 9-0-0 06-11-10
!status work item 07-10-24
!status received 07-10-02
!priority Medium
!difficulty Hard
!subject Holder container
!summary
(See proposal.)
!problem
It not possible in Ada to declare an object of an indefinite type that can hold any value of that type -- the language requires an initialization value and for the object to be constrained by that value. Worse, components of indefinite types are illegal.
However, it is often useful to have objects and components of indefinite types. One example is the classwide type at the root of a tree of types. It's not uncommon to have operations that produce values of such a type, and to want to store those values as components of a type.
This can be done using access types and explicit storage management. However, this is error-prone. Moreover, we've defined containers to eliminate the need for explicit memory management of common data structures.
Thus it is appropriate to have have a container to handle this operation.
!proposal
Define a singleton container as follows:
generic type Element_Type (<>) is private; with function "=" (Left, Right : Element_Type) return Boolean is <>; package Ada.Containers.Indefinite_Holders is pragma Preelaborate (Indefinite_Holders); -- This package provides a "holder" of a definite type that contains -- a single value of an indefinite type. -- This allows one to effectively declare an uninitialized variable -- or component of an indefinite type.
type Holder is tagged private; pragma Preelaborable_Initialization (Holder);
Empty_Holder : constant Holder;
function "=" (Left, Right : Holder) return Boolean; -- If Left and Right denote the same holder object, then the function returns True. -- Otherwise, it compares the element contained in Left to the element contained in -- Right using the generic formal equality operator, returning the result of that -- operation. Any exception raised during the evaluation of element equality is -- propagated.
function To_Holder (New_Item : Element_Type) return Holder; -- Returns a non-empty holder containing an element initialized to New_Item.
function Is_Empty (Container : Holder) return Boolean; -- Returns True if the holder is empty, and -- False if it contains an element.
procedure Clear (Container : in out Holder); -- Removes the element from Container.
function Element (Container : Holder) return Element_Type; -- If Container is empty, Constraint_Error is propagated. -- Otherwise, returns the element stored in Container.
procedure Replace_Element (Container : in out Holder; New_Item : in Element_Type); -- Replace_Element assigns the value New_Item into Container, replacing -- any preexisting content of Container. Container is not empty -- after a successful call to Replace_Element.
procedure Query_Element (Container : in Holder; Process : not null access procedure (Element : in Element_Type)); -- If Container is empty, Constraint_Error is propagated. -- Otherwise, Query_Element calls Process.all with the contained element as -- the argument. Program_Error is raised if Process.all tampers with the elements -- of Container. Any exception raised by Process.all is propagated.
procedure Update_Element (Container : in Holder; Process : not null access procedure (Element : in out Element_Type)); -- If Container is empty, Constraint_Error is propagated. -- Otherwise, Update_Element calls Process.all with the contained element as -- the argument. Program_Error is raised if Process.all tampers with the elements -- of Container. Any exception raised by Process.all is propagated.
procedure Move (Target : in out Holder; Source : in out Holder); -- If Target denotes the same object as Source, then Move has no effect. -- Otherwise, the element contained by Source (if any) is removed from Source -- and inserted into Target, replacing any preexisting content. Source is empty -- after a successful call to Move.
private -- ... Not specified by the language. end Ada.Containers.Indefinite_Holders;
!wording
The language-defined generic package Containers.Indefinite_Holders provides private type Holder and a set of operations for that type. A holder container holds a single element of an indefinite type.
A holder containers allows the declaration of an object that can be used like an uninitialized variable or component of an indefinite type.
A holder container may be empty. An empty holder does not contain an element.
Static Semantics
The generic library package Containers.Indefinite_Holders has the following declaration:
generic type Element_Type (<>) is private; with function "=" (Left, Right : Element_Type) return Boolean is <>; package Ada.Containers.Indefinite_Holders is pragma Preelaborate (Indefinite_Holders);
type Holder is tagged private; pragma Preelaborable_Initialization (Holder);
Empty_Holder : constant Holder;
function "=" (Left, Right : Holder) return Boolean;
function To_Holder (New_Item : Element_Type) return Holder;
function Is_Empty (Container : Holder) return Boolean;
procedure Clear (Container : in out Holder);
function Element (Container : Holder) return Element_Type;
procedure Replace_Element (Container : in out Holder; New_Item : in Element_Type);
procedure Query_Element (Container : in Holder; Process : not null access procedure (Element : in Element_Type));
procedure Update_Element (Container : in Holder; Process : not null access procedure (Element : in out Element_Type));
procedure Move (Target : in out Holder; Source : in out Holder);
private -- ... Not specified by the language. end Ada.Containers.Indefinite_Holders;
The actual function for the generic formal function "=" on Element_Type values is expected to define a reflexive and symmetric relationship and return the same result value each time it is called with a particular pair of values. If it behaves in some other manner, the function "=" on holder values returns an unspecified value. The exact arguments and number of calls of this generic formal function by the function "=" on holder values are unspecified.
AARM Ramification: If the actual function for "=" is not symmetric and consistent, the result returned by any of the functions defined to use "=" cannot be predicted. The implementation is not required to protect against "=" raising an exception, or returning random results, or any other “bad” behavior. And it can call "=" in whatever manner makes sense. But note that only the results of the function "=" is unspecified; other subprograms are not allowed to break if "=" is bad.
The type Holder is used to represent holder containers. The type Holder needs finalization (see 7.6).
Empty_Holder represents an empty holder object. If an object of type Holder is not otherwise initialized, it is initialized to the same value as Empty_Holder.
[Some operations of this generic package have access-to-subprogram parameters. To ensure such operations are well-defined, they guard against certain actions by the designated subprogram. In particular, some operations check for "tampering with elements" of a container because they depend on elements of the container not being replaced.]
A subprogram is said to tamper with elements of a holder object H if: * It clears the element contained by H, that is, it calls the Clear procedure with H
as a parameter;
* It replaces the element contained by H, that is, it calls the Replace_Element
procedure with H as a parameter;
* It calls the Move procedure with H as a parameter; * It finalizes H.
AARM Reason: Complete replacement of an element can cause its memory to be deallocated while another operation is holding onto a reference to it. That can't be allowed. However, a simple modification of (part of) an element is not a problem, so Update_Element does not cause a problem.
function "=" (Left, Right : Holder) return Boolean;
If Left and Right denote the same holder object, then the function returns True. Otherwise, it compares the element contained in Left to the element contained in Right using the generic formal equality operator, returning the result of that operation. Any exception raised during the evaluation of element equality is propagated.
AARM Implementation Note: This wording describes the canonical semantics. However, the order and number of calls on the formal equality function is unspecified, so an implementation need not call the equality function if the correct answer can be determined without doing so.
function To_Holder (New_Item : Element_Type) return Holder;
Returns a non-empty holder containing an element initialized to New_Item.
function Is_Empty (Container : Holder) return Boolean;
Returns True if the holder is empty, and False if it contains an element.
procedure Clear (Container : in out Holder);
Removes the element from Container. Container is empty after a successful Clear operation.
function Element (Container : Holder) return Element_Type;
If Container is empty, Constraint_Error is propagated. Otherwise, returns the element stored in Container.
procedure Replace_Element (Container : in out Holder; New_Item : in Element_Type);
Replace_Element assigns the value New_Item into Container, replacing any preexisting content of Container. Container is not empty after a successful call to Replace_Element.
procedure Query_Element (Container : in Holder; Process : not null access procedure (Element : in Element_Type));
If Container is empty, Constraint_Error is propagated. Otherwise, Query_Element calls Process.all with the contained element as the argument. Program_Error is raised if Process.all tampers with the elements of Container. Any exception raised by Process.all is propagated.
AARM Reason: The "tamper with the elements" check is intended to prevent the Element parameter of Process from being modified or deleted outside of Process. The check prevents data loss (if Element_Type is passed by copy) or erroneous execution (if Element_Type is an unconstrained type).
procedure Update_Element (Container : in Holder; Process : not null access procedure (Element : in out Element_Type));
If Container is empty, Constraint_Error is propagated. Otherwise, Update_Element calls Process.all with the contained element as the argument. Program_Error is raised if Process.all tampers with the elements of Container. Any exception raised by Process.all is propagated.
AARM Implementation Note: The Element parameter of Process.all may be constrained even if Element_Type is unconstrained.
procedure Move (Target : in out Holder; Source : in out Holder);
If Target denotes the same object as Source, then Move has no effect. Otherwise, the element contained by Source (if any) is removed from Source and inserted into Target, replacing any preexisting content. Source is empty after a successful call to Move.
Bounded Errors
It is a bounded error for the actual function associated with a generic formal subprogram, when called as part of an operation of this package, to tamper with elements of any Holder parameter to the operation. Either Program_Error is raised, or the operation works as defined on the value of the Holder either prior to, or subsequent to, some or all of the modifications to the Holder.
[Editor's note: This is from AI05-0022-1.]
It is a bounded error to call any subprogram declared in the visible part of Containers.Indefinite_Holders when the associated container has been finalized. If the operation takes Container as an IN OUT parameter, then it raises Constraint_Error or Program_Error. Otherwise, the operation either proceeds as it would for an empty container, or it raises Constraint_Error or Program_Error.
[Editor's note: This is from AI05-0027-1.]
Implementation Requirements
No storage associated with a holder object shall be lost upon assignment or scope exit.
The execution of an assignment_statement for a holder shall have the effect of copying the element (if any) from the source holder object to the target holder object.
AARM Implementation Note: An assignment of a holder is a "deep" copy; that is the elements are copied as well as the data structures. We say "effect of" in order to allow the implementation to avoid copying elements immediately if it wishes. For instance, an implementation that avoided copying until one of the containers is modified would be allowed.
Implementation Advice
Move should not copy elements, and should minimize copying of internal data structures.
AARM Implementation Note: Usually that can be accomplished simply by moving the pointer(s) to the internal data structures from the Source holder to the Target holder.
If an exception is propagated from a holder operation, no storage should be lost, nor should the element be removed from a holder unless specified by the operation.
AARM Reason: This is important so that programs can recover from errors. But we don't want to require heroic efforts, so we just require documentation of cases where this can't be accomplished.
!discussion
Note that it isn't necessary to define a definite version of this container; that would just be a complicated way to write "A : Element_Type".
!example
!corrigendum A.18.17
!comment This is intended to force a conflict. The fully formated text is in the conflict file.
@dinsc The language-defined generic package Containers.Indefinite_Holders provides private type Holder and a set of operations for that type. A holder container holds a single element of an indefinite type.
!ACATS test
ACATS C-Test(s) are necessary for this package.
!appendix

From: Tucker Taft
Date: Tuesday, October 2, 2007  8:06 PM

As part of my homework for ASIS SI-24, the semantic
model, I am trying to work out a version using tagged
types rather than untagged discriminated types.
One thing we agreed would be necessary is some kind
of singleton container that can be used to store
class-wide values returned from various functions.
I have constructed such a container, which I chose
to call a "holder."  I have attached the proposed
spec and body, which I tried to make similar to
indefinite_vectors, etc.  There seems no particular
value for a holder of "definite" elements, so I
didn't bother to define both a "definite" version
and an "indefinite" version.  This one handles
either.

As you may remember, the key problem I saw with using
tagged types for the ASIS semantic model is that the operations
will often be designed to return a class-wide object, but then
the caller may want to be able to store this into
a preexisting local variable, or the field of some
record.  That doesn't work for a class-wide type.
However, a "holder" can be used for this purpose.

Comments welcome.  My intent is to define a Holder type
for each of the main kinds of views/entities.
The user could of course declare more if they
wanted finer control.

---

with Ada.Streams;
with Ada.Finalization;
generic
    type Element_Type (<>) is private;
package Ada_Containers_Holders is
    -- This package provides a "holder" of a definite type that contains
    -- a single value of an indefinite type.
    -- This allows one to effectively declare an uninitialized variable
    -- of an indefinite type.

    type Holder is tagged private;

    procedure Replace_Contents(
      Container : in out Holder; Contents : Element_Type);
      -- This assigns Contents into the Container, replacing
      -- any preexisting content of Container.

    generic
        with procedure Update(Contents : in out Element_Type);
    procedure Update_Contents(Container : in out Holder);
      -- This calls the given procedure with the contents, if
      -- any, of the Container.  It is a no-op if the
      -- container is empty.

    procedure Move(Target : in out Holder; Source : in out Holder);
      -- This moves the contents of Source into Target, leaving
      -- Source empty, and replacing any preexisting content of Target.
      -- This is a no-op if Target and Source are the same object.

    function Contents(Container : Holder) return Element_Type;
      -- This returns the element, if any, stored in the holder.
      -- If no element is stored in the holder, Constraint_Error is raised.

    function Is_Empty(Container : Holder) return Boolean;
      -- This returns True if the holder is empty, and
      -- False if it contains an element.

private
    type Element_Ptr is access Element_Type;
    type Holder is new Ada.Finalization.Controlled with record
	Contents : Element_Ptr := null;
    end record;

    procedure Adjust(Container : in out Holder);
      -- This makes a copy of Container.Contents.all 
      -- if Container.Contents non-null

    procedure Finalize(Container : in out Holder);
      -- This calls Unchecked_Deallocation on Container.Contents

    function "="(Left, Right : Holder) return Boolean;
      -- Make sure that equality works

    -- Provide stream attributes
    use Ada.Streams;

    procedure Write(Stream : access Root_Stream_Type'Class;
      Container : in Holder);

    for Holder'Write use Write;

    procedure Read(Stream : access Root_Stream_Type'Class;
      Container : out Holder);

    for Holder'Read use Read;

end Ada_Containers_Holders;

---

with Ada.Unchecked_Deallocation;
package body Ada_Containers_Holders is
    -- This package provides a definite type that contains
    -- a single value of an indefinite type.

    ------------- Local and private declarations --------------

    procedure Free is new 
      Ada.Unchecked_Deallocation(Element_Type, Element_Ptr);

    procedure Adjust(Container : in out Holder) is
      -- This makes a copy of Container.Contents.all if 
      -- Container.Contents non-null
    begin
	if Container.Contents /= null then
	    Container.Contents := new Element_Type'(Container.Contents.all);
	end if;
    end Adjust;

    procedure Finalize(Container : in out Holder) is
      -- This calls Unchecked_Deallocation on Container.Contents
    begin
	Free(Container.Contents);
    end Finalize;

    function "="(Left, Right : Holder) return Boolean is
      -- Make sure that equality works
    begin
	return Left.Contents = Right.Contents or else
	  (Left.Contents /= null and then Right.Contents /= null
	   and then Left.Contents.all = Right.Contents.all);
    end "=";

    -- Provide stream attributes
    procedure Write(Stream : access Root_Stream_Type'Class;
      Container : in Holder) is
	-- Write a boolean indicating whether Holder contains
	-- an element, and if True, write out the element.
	Is_Present : constant Boolean := Container.Contents /= null;
    begin
	Boolean'Write(Stream, Is_Present);
	if Is_Present then
	    Element_Type'Output(Stream, Container.Contents.all);
	end if;
    end Write;

    procedure Read(Stream : access Root_Stream_Type'Class;
      Container : out Holder) is
	-- Read a boolean, and then if true, read the element
	Is_Present : constant Boolean := Boolean'Input(Stream);
    begin
	Free(Container.Contents);
	if Is_Present then
	    Container.Contents := new Element_Type'(Element_Type'Input(Stream));
	end if;
    end Read;

    ------------ Visible Subprograms ---------------

    procedure Replace_Contents(
      Container : in out Holder; Contents : Element_Type) is
      -- This assigns Contents into the Container, replacing
      -- any preexisting content of Container.
    begin
	Free(Container.Contents);
        Container.Contents := new Element_Type'(Contents);
    end Replace_Contents;

    procedure Update_Contents(Container : in out Holder) is
      -- This calls the given procedure with the contents, if
      -- any, of the Container.  It is a no-op if the
      -- container is empty.
    begin
	if Container.Contents /= null then
	    Update(Container.Contents.all);
	end if;
    end Update_Contents;

    procedure Move(Target : in out Holder; Source : in out Holder) is
      -- This moves the contents of Source into Target, leaving
      -- Source empty, and replacing any preexisting content of Target.
      -- This is a no-op if Target and Source are the same object.
    begin
	if Target.Contents /= Source.Contents then
	    Free(Target.Contents);
	    Target.Contents := Source.Contents;
	    Source.Contents := null;
	end if;
	    -- NOTE: If Target.Contents = Source.Contents then
	    --       either both are null, or Target and Source are
	    --       the same object (or so I claim).
    end Move;

    function Contents(Container : Holder) return Element_Type is
      -- This returns the element, if any, stored in the holder.
      -- If no element is stored in the holder, Constraint_Error is raised.
    begin
	return Container.Contents.all;
    end Contents;

    function Is_Empty(Container : Holder) return Boolean is
      -- This returns True if the holder is empty, and
      -- False if it contains an element.
    begin
	return Container.Contents = null;
    end Is_Empty;

end Ada_Containers_Holders;

****************************************************************

From: Pascal Leroy
Date: Wednesday, October 3, 2007  12:53 AM

> Comments welcome.  My intent is to define a Holder type for 
> each of the main kinds of views/entities.
> The user could of course declare more if they wanted finer control.

It would seem to make sense to have a procedure Clear to empty the holder.
To some extent, Clear and Is_Empty go together.

****************************************************************

From: Jean-Pierre Rosen
Date: Wednesday, October 3, 2007  2:33 AM

> As part of my homework for ASIS SI-24, the semantic
> model, I am trying to work out a version using tagged
> types rather than untagged discriminated types.
> One thing we agreed would be necessary is some kind
> of singleton container that can be used to store
> class-wide values returned from various functions.
> I have constructed such a container, which I chose
> to call a "holder."  I have attached the proposed
> spec and body, which I tried to make similar to
> indefinite_vectors, etc.  There seems no particular
> value for a holder of "definite" elements, so I
> didn't bother to define both a "definite" version
> and an "indefinite" version.  This one handles
> either.

Looks nice and useful. So useful actually that it has nothing special to 
do with ASIS. Even if we take the opportunity to put this in ASIS05, is 
there a problem in naming it ada.containers.holders ? This could 
encourage implementations (even if they do not provide ASIS) to provide 
this one as part of the standard library.

****************************************************************

From: Tucker Taft
Date: Wednesday, October 3, 2007  12:24 PM

It was my hope that it could be named
Ada.Containers.Holders in the expectation that
it would be the first of various additions to the
Containers hierarchy.

I think I'll add something like "Clear,"
but call it "Set_Empty" to make
its relationship to "Is_Empty" crystal "clear".  ;-)

I was also considering changing the name of the formal
type to "Contents_Type" from "Element_Type," to
be consistent with the use of the function name "Contents"
rather than "Element".

****************************************************************

From: Tucker Taft
Date: Wednesday, October 3, 2007  12:41 PM

Actually, I guess "Clear" is used consistently
to mean Set_Empty in the other Containers, so
I should probably use that here as well.

****************************************************************

From: Pascal Leroy
Date: Wednesday, October 3, 2007  2:05 AM

> Actually, I guess "Clear" is used consistently to mean 
> Set_Empty in the other Containers, so I should probably use 
> that here as well.

I think consistency with the other containers would be a good thing.  So I
prefer Clear to Set_Empty and Element_Type to Content_Type.  No point in
changing names unless the semantics are clearly distinct.

****************************************************************

From: Randy Brukardt
Date: Wednesday, October 24, 2007  7:33 PM

For the record, this goes for all of the names (and wording!) in this container:

Update_Element, not Update_Contents;
Query_Element needs to exist;
Element, not Contents, to retrieve the element;
Replace_Element, not Replace_Contents;
and, finally, the operations need to be declared in the same order as in the 
other containers (otherwise, John will beat me up during editorial review).

I'll make all of these changes in the AI, so we don't (I hope) have to argue
about that for hours.

****************************************************************

From: Randy Brukardt
Date: Wednesday, October 24, 2007  8:06 PM

Having written that, I found more:
   Function wording starts with "Returns", not "This returns";
   Lots of other wording issues (copy the Vector container wording
     as closely as possible);
   The 2nd parameter name for Replace_Element should be New_Item;
   Query_Element and Update_Element should take an access-to-subprogram,
     not be generic.

Possibly controversial:
   Query_Element and Update_Element should raise Constraint_Error if the holder
   is empty to be consistent with Element (Tucker called it "Contents"). For existing
   containers, this is a Bounded_Error in all three cases, but none of the error
   possibilities is no-op (which is what Tucker used for Update_Element). It seems
   to me that defining this as a no-op is dangerous, because the update will not happen
   without any indication as to why; the possibility of using the existing (random)
   element only makes sense for definite containers.

   We also need the tampering and propagation rules.

   We should have a To_Holder function:
       function To_Holder (New_Item : Element_Type) return Holder;
          -- Returns a non-empty holder containing an element initialized to New_Item.
   This is similar to the To_Vector function of a vector. (But this one is not as common as
   the other operations.)

Yes, I looked at every routine in Vectors to see if it was relevant. That's probably
the only way to do this.

Amazing how many details there are even in such a simple container...

****************************************************************

From: Stephen W. Baird
Date: Monday, November 19, 2007  5:04 PM

Rich Paige, who has implemented all of the other
container generics for IBM/Rational, had the following
questions about differences between the Holder spec
and the other container specs (in addition to noticing
the parameter mode problem with Clear which was fixed
in Fairfax):

    Should  the holder generic take a formal "=" operator?
    Should  the holder generic export an explicitly declared "=" operator?
    Should  the spec include a Preelaborate pragma and a
        Preelaborable_Initialization pragma for the holder type?
    Should  the spec export an Empty_Holder constant?

  ----

        Many happy returns of Eeyore's birthday," said Pooh.

        "Oh, is that what it is?"

        "What are you giving him, Owl?"

        "What are you giving him, Pooh?"

        I'm giving  him a Useful Pot to Keep Things In, and I
        wanted to ask you "

        "Is this it?" said Owl, taking it out of Pooh's paw.

        "Yes, and I wanted to ask you -- "

        "Somebody has been keeping honey in it," said Owl.

        "You can keep anything in  it,"  said  Pooh  earnestly.
        "It's Very Useful like that".

           -- A.A. Milne

****************************************************************

From: Randy Brukardt
Date: Monday, November 19, 2007  5:11 PM

...
>     Should  the holder generic take a formal "=" operator?

I don't think so, because there is no Find operation that would use it.

>     Should  the holder generic export an explicitly declared "=" operator?

I thought it did (doesn't everything?). Of course, then we need the formal
"=" and all of the wording that goes with that. Ugh.

>     Should  the spec include a Preelaborate pragma and a
>         Preelaborable_Initialization pragma for the holder type?

Yes, of course.

>     Should  the spec export an Empty_Holder constant?

I suppose. Not sure how I could have missed that (and "="). Probably just
didn't start at the very top when looking through Vectors.

Anyone else have thoughts? I suppose these are too much change to do without
bringing it back for another ARG approval.

****************************************************************

From: Ed Schonberg
Date: Monday, November 19, 2007  5:37 PM

>>     Should  the holder generic take a formal "=" operator?
>
> I don't think so, because there is no Find operation that would use  
> it.

But the re-exported "=" will most likely use it, as you note.

>
>>     Should  the holder generic export an explicitly declared "="  
>> operator?
>
> I thought it did (doesn't everything?). Of course, then we need the  
> formal "=" and all of the wording that goes with that. Ugh.
>
>>     Should  the spec include a Preelaborate pragma and a
>>         Preelaborable_Initialization pragma for the holder type?
>
> Yes, of course.
>
>>     Should  the spec export an Empty_Holder constant?
>
> I suppose. Not sure how I could have missed that (and "="). Probably just
> didn't start at the very top when looking through Vectors.
>
> Anyone else have thoughts? I suppose these are too much change to  
> do without bringing it back for another ARG approval.

This may be settled by e-mail, these are straightforward consistency  
changes  (said he in his naive optimism).

****************************************************************

From: Robert A. Duff
Date: Monday, November 19, 2007  5:58 PM

> This may be settled by e-mail, these are straightforward consistency  changes
> (said he in his naive optimism).

In general, I'm in favor of settling things by e-mail, and I encourage the new
chair to encourage that.  I hate to travel half-way round the world to deal
with obvious stuff.  Anyway, this one seems straightforward.

I'm also in favor of including the Pooh story in the AARM.  ;-)

****************************************************************

From: Randy Brukardt
Date: Monday, November 19, 2007  6:28 PM

Has Tampa been moved to Europe? ;-)

The problem, of course, is that what is obvious to me and Ed may not be
obvious to everyone. We had a number of incidents in the past where the
integrity of the leadership of the ARG was questioned, and thus we became
rather conservative in handling changes - it is hard to argue with a vote of
the entire ARG.

We could of course vote to approve the "obvious" changes of the editor each
meeting, but I suspect that such a resolution would end up with a 2-0-8
vote, as no one would want to vote for a blank check.

Note that we had a case where an "obvious" AI (AI-13) was reversed by the
full ARG in Fairfax. (We also had more "obvious" AIs in Fairfax than usual
because we did not manage to finish all of them at the previous meeting,
leaving twelve of them to carry over.) Moreover, the review of "obvious" AIs
sometimes finds additional problems beyond just typos. And they provide a
needed break from the really tough nuts.

All of that said, I don't have a problem in this particular case in making
the improvements by e-mail. (WG 9 still will have to approve it in any case,
plus a second review when we make a Corrigendum or other standards document.
And there is plenty of precident for these particular changes.) I think we
would need to deal with E-mail approval as we do with initial comments.

Does anyone out there want additional ARG review of these changes to
AI05-0069-1 (package Ada.Containers.Holder)? So far, no one has indicated
that.

****************************************************************

From: Tucker Taft
Date: Monday, November 19, 2007  7:42 PM

Yes, Yes, Yes, Yes.  ;-)
Now it is even more useful!

****************************************************************

From: John Barnes
Date: Tuesday, November 20, 2007  2:10 AM

> Does anyone out there want additional ARG review of these changes to
> AI05-0069-1 (package Ada.Containers.Holder)? So far, no one has indicated
> that.


Well you have made rather a lot of changes by now and although they seem
straightforward, I think it would be good to circulate the result soon while
it is still in our minds (rather than just saying go read the database). Of
course, it will be sent for editorial review along with a whole lot of
others in due course but it won't perhaps receive the scrutiny it deserves
by then.

****************************************************************

From: Randy Brukardt
Date: Tuesday, November 20, 2007  9:47 PM

Well, I haven't made any changes at all yet -- I was trying to find out if
that was a good idea first. I think I have my answer to that, so I'll get to
work.

There is one remaining question: we didn't change the status of this AI.
That leaves it in limbo for the time being (we're not intending to forward
Amendment AIs to WG 9). But we're planning to use this particular package in
ASIS, and waiting for the next Amendment or container TR probably would
leave it undefined (formally) when ASIS goes to Standardization (not much is
happening with the container TR - I haven't had time to push the
development). Is that OK? Or should we make this a Binding Interpretation?
(It's surely short enough, and there is no sane incompatibility.)

****************************************************************

From: Randy Brukardt
Date: Tuesday, November 20, 2007  11:27 PM

Since we're enjoyably thinking about this package (rather than one of
Steve Baird's problems ;-), here's some additional consistency questions:

 (1) All of the indefinite containers start with "Indefinite_". A holder
     is defined only for an indefinite element type. Should this package
     really be called "Indefinite_Holders"?? It would be inconsistent for
     it not to be named that way. (Side-effect: the name makes it more
     obvious what these are for. At least if you know what an indefinite
     type is.)

 (2) Adding the formal "=" means that we'll need AI05-0071-1 to be finished
     and adopted before this will actually work with the ASIS definition.
     (That's probably a good thing.)

****************************************************************

From: Randy Brukardt
Date: Tuesday, November 20, 2007  11:27 PM

> Well you have made rather a lot of changes by now and although they seem
> straightforward, I think it would be good to circulate the result 
> soon while it is still in our minds (rather than just saying go read the 
> database).

Ask and ye shall receive. Even if you didn't *really* mean it. Below find the entire
wording section for AI05-0069-1, as revised and all of the missing chunks filled in
(I hope). The rest of the AI is essentially unchanged.

[Editor's note: This is from version /02 of the AI, not repeated here.]

****************************************************************

From: Robert I. Eachus
Date: Wednesday, November 21, 2007  8:13 AM

The wording Randy sent says:

If Left and Right denote the same holder object, then the function returns True.
Otherwise, it compares the element contained in Left to the element contained in
Right using the generic formal equality operator, returning the result of that
operation. Any exception raised during the evaluation of element equality is propagated.

  AARM Implementation Note: This wording describes the canonical semantics.
  However, the order and number of calls on the formal equality function
  is unspecified, so an implementation can call it as many or as few times
  as it needs to get the correct answer.
  
There is stilll a bit of we all know what is meant left in the definition of
Empty_Holder and "=" for the Holder type.  We "know" that Holder is an access type,
and that Empty_Holder returns null--or that that is the intended semantics even
if someone provides an implementation using a file or database to provide
persistant semantics.  The intended semantics is, I am sure:

function "=" (Left, Right: Holder) return Boolean is
begin
   if Is_Empty(Left) then return Is_Empty(Right);
   else return Left.all = Right.all;
   end  if;
end "=";

But if this is the intended definition, why not just say so?  Note that even
if the implementation does not choose to make Holder an access type, that this
definition is correct. There is a "better" definition, but it requires a kludge.
 If type Holder is defined (in the private part) as:

type Hidden is access Element_Type;
type Holder is new Hidden;

then you can use this definition: 

function "=" (Left, Right: Holder) return Boolean is
begin
   if Hidden(Left) = Hidden(Right) then return True;
   elsif Is_Empty(Left) then return Is_Empty(Right);
   else return Left.all = Right.all;
   end  if;
end "=";

Is there a point to all this?  Sure.  I really don't like the phrase
"can call it as many or as few times as it needs to get the correct answer" above.
We know that any implementation that calls what may be a deep comparison more than
once is just bad code. Zero and one are right answers, and the two examples given
show that there are variations that call the formal "=" more or less often, but never
more than once per call.  I'd be satisfied with a change to:

 AARM Implementation Note: This wording describes the canonical semantics.
  The circumstances where the equality operator for Holder calls the formal equality function,
  and with which parameters, are unspecified.

****************************************************************

From: Randy Brukardt
Date: Monday, November 26, 2007  8:56 PM

...
> Is there a point to all this?  Sure.

I *was* beginning to wonder. ;-)

> I really don't like the phrase  "can call it as many or as few times as it needs
> to get the correct answer" above.

That wording is just copied from the other containers. We want this one to be
as little different as possible...

> We know that any implementation that calls
> what may be a deep comparison more than once is just bad code.  Zero and one are
> right answers, and the two examples given show that there are variations that
> call the formal "=" more or less often, but never more than once per call.

There is nothing in the language or its definition to prevent bad code. And
"unspecified" here means what it says; an implementation which calls "=" 47
times is still correct vis-a-vis the standard. OTOH, I can see your point that
the note seems to encourage a bad implementation (although I can't quite see
what purpose an implementor would have with such an implementation).

> I'd be
> satisfied with a change to:
>
>
> AARM Implementation Note: This wording describes the canonical semantics.
>  The circumstances where the equality operator for Holder calls the formal
>  equality function, and with which parameters, are unspecified.

That just repeats the language definition, which is rarely worthwhile for
an AARM note. How about saying instead:

  AARM Implementation Note: This wording describes the canonical semantics.
  However, the order and number of calls on the formal equality function
  is unspecified, so an implementation does not need to call it if the
  implementation can determine the correct answer without doing so.

Meaning that we don't talk about the possibility of making extra
(unnecessary) calls, even though that is allowed.

****************************************************************

From: Robert I. Eachus
Date: Tuesday, November 27, 2007  4:21 PM

That's fine.  I would probably say "so an implementation need not call 
the equality function if the answer can be determined without doing 
so."  But that's just wordsmithing.

****************************************************************



Questions? Ask the ACAA Technical Agent