CVS difference for ai12s/ai12-0240-4.txt

Differences between 1.1 and version 1.2
Log of other versions for file ai12s/ai12-0240-4.txt

--- ai12s/ai12-0240-4.txt	2019/01/11 02:30:20	1.1
+++ ai12s/ai12-0240-4.txt	2019/01/18 03:21:56	1.2
@@ -6,82 +6,218 @@
 !difficulty Hard
 !subject Pointer ownership for Abstract Data Types !summary
 
-We introduce the notion of "pointer ownership" to allow us to define the "Global" aspects of the visible operations of an abstract data type, without being concerned with appropriately-managed internal uses of access types.  We call these properly managed
 internal access types, "ownership-based" access types for now. A more concise term might be adopted at some point.
+We introduce the notion of "pointer ownership" to allow us to define the
+"Global" aspects of the visible operations of an abstract data type, without
+being concerned with appropriately-managed internal uses of access types.  We
+call these properly managed internal access types, "ownership-based" access
+types for now. A more concise term might be adopted at some point.
 
 !problem
 
-Assuming that we have static data-race checks (AI12-0267-1), it is important that the Global aspects of abstract data type (ADT) operations introduce as few conflicts as possible. In particular, the Global aspects of the container operations need to imply
 a minimal use of shared variables.  Otherwise, they could not be used safely in any sort of multi-threaded situation.
+Assuming that we have static data-race checks (AI12-0267-1), it is important
+that the Global aspects of abstract data type (ADT) operations introduce as few
+conflicts as possible. In particular, the Global aspects of the container
+operations need to imply a minimal use of shared variables.  Otherwise, they
+could not be used safely in any sort of multi-threaded situation.
+
+Currently, the only way to describe the dereferencing of an access object in the
+context of a Global aspect is by the "access T" or "<package_name>" form of
+specification, which will tend to lump together all objects of the same
+container type, when in fact two distinct objects of a container type almost
+certainly share no storage.  We believe we need some better way to define the
+global side effects of ADT operations which reflects the true amount of data
+sharing, or lack thereof, between objects of an ADT that uses pointers
+internally.
 
-Currently, the only way to describe the dereferencing of an access object in the context of a Global aspect is by the "access T" or "<package_name>"
-form of specification, which will tend to lump together all objects of the same container type, when in fact two distinct objects of a container type almost certainly share no storage.  We believe we need some better way to define the global side effects 
of ADT operations which reflects the true amount of data sharing, or lack thereof, between objects of an ADT that uses pointers internally.
-
 !proposal
-
-Handling pointer dereferences has always been a challenge for formal analysis, with approaches such as "separation logic" generally requiring more formalism than would be appropriate even for a skilled programmer.
-The concept of "pointer ownership" or "object ownership" represents a simpler alternative approach, and reflects a typical way in which most pointers are actually used in the implementation of many ADTs. When pointers have "ownership," this means that the
 heap object they designate has exactly one "owning" pointer, and when the owning pointer is set to null, the heap object can be safely reclaimed.  Although there might be other pointers designating the heap object under certain circumstances, these other 
pointers are recognized as being "secondary"
-references, which can be managed in a way to ensure that no such secondary references are usable after the "owning" pointer is set to null.
 
-We propose to add "ownership-based" access types to the language, with aspect Ownership => True, and with four distinct kinds of subtypes of such access types, as determined by an Access_Kind aspect, specifiable on an object or subtype declaration:
+Handling pointer dereferences has always been a challenge for formal analysis,
+with approaches such as "separation logic" generally requiring more formalism
+than would be appropriate even for a skilled programmer. The concept of "pointer
+ownership" or "object ownership" represents a simpler alternative approach, and
+reflects a typical way in which most pointers are actually used in the
+implementation of many ADTs. When pointers have "ownership," this means that the
+heap object they designate has exactly one "owning" pointer, and when the owning
+pointer is set to null, the heap object can be safely reclaimed.  Although there
+might be other pointers designating the heap object under certain circumstances,
+these other pointers are recognized as being "secondary" references, which can
+be managed in a way to ensure that no such secondary references are usable after
+the "owning" pointer is set to null.
+
+We propose to add "ownership-based" access types to the language, with aspect
+Ownership => True, and with four distinct kinds of subtypes of such access
+types, as determined by an Access_Kind aspect, specifiable on an object or
+subtype declaration:
  * Access_Kind => Owner -- owner subtypes
  * Access_Kind => Borrower -- borrower subtypes
  * Access_Kind => Observer -- observer subtypes
  * Access_Kind => Unmanaged -- unmanaged subtypes
-
-Operations that reference or update a heap object designated by an ownership-based access object may treat the designated object as though it were a subcomponent of the composite object containing the object's owning pointer.  An object is "directly owned
" by its owning pointer, and simply "owned" by both its direct owner as well as by the owner(s) of the (heap) object of which the owning pointer is a subcomponent. What this means as far as the Global aspect is that there is no need to use "access T" or "<
package_name>" to recognize dereferences of ownership-based access objects.  Instead, the Global aspect should recognize that these dereferences are equivalent to referencing subcomponents of the owner(s), and including an object containing an owner in the
 global variable set for the IN, IN OUT, or OUT mode implicitly includes all the objects owned, directly or indirectly, by this owner.
 
-Any composite type with an owning object as a subcomponent becomes a by-reference type, much like any composite type with a tagged, inherently limited, or volatile subcomponent is a by-reference type.
-This simplifies various rules by eliminating implicit copying of objects containing owning pointers.
+Operations that reference or update a heap object designated by an
+ownership-based access object may treat the designated object as though it were
+a subcomponent of the composite object containing the object's owning pointer.
+An object is "directly owned" by its owning pointer, and simply "owned" by both
+its direct owner as well as by the owner(s) of the (heap) object of which the
+owning pointer is a subcomponent. What this means as far as the Global aspect is
+that there is no need to use "access T" or "<package_name>" to recognize
+dereferences of ownership-based access objects.  Instead, the Global aspect
+should recognize that these dereferences are equivalent to referencing
+subcomponents of the owner(s), and including an object containing an owner in
+the global variable set for the IN, IN OUT, or OUT mode implicitly includes all
+the objects owned, directly or indirectly, by this owner.
+
+Any composite type with an owning object as a subcomponent becomes a
+by-reference type, much like any composite type with a tagged, inherently
+limited, or volatile subcomponent is a by-reference type. This simplifies
+various rules by eliminating implicit copying of objects containing owning
+pointers.
+
+Explicit copying of objects containing owning pointers (e.g. on assignment or
+function return) automatically performs a "deep" copy, reflecting the model that
+an object designated by an owning pointer is treated like a component.
+Similarly streaming an owning pointer is defined to stream the designated
+object.
+
+Because owning pointers themselves are of an access type, they are implicitly
+copied as part of by-copy parameter passing.  They are also, of course, copied
+as part of an assignment or function return.  Unlike the case of a composite
+object with one of these as a component, we don't have the option of making them
+into a by-reference type, and thereby eliminating cases of implicit copying.
+Furthermore, even in an assignment statement, it is not always clear that you
+would want to do a deep copy when such an access object is assigned to another.
+It depends heavily on the context.  For example, if you wanted to create a
+pointer that was to walk over an existing tree structure, you certainly wouldn't
+want the creation of that temporary pointer to result in the creation of a copy
+of the tree.  This leads us to define the four kinds of ownership-based access
+subtypes mentioned above, and also to define some attributes to be used for
+specifying explicitly how the copying of an acces object is to be performed.
 
-Explicit copying of objects containing owning pointers (e.g. on assignment or function return) automatically performs a "deep" copy, reflecting the model that an object designated by an owning pointer is treated like a component.  Similarly streaming an o
wning pointer is defined to stream the designated object.
-
-Because owning pointers themselves are of an access type, they are implicitly copied as part of by-copy parameter passing.  They are also, of course, copied as part of an assignment or function return.  Unlike the case of a composite object with one of th
ese as a component, we don't have the option of making them into a by-reference type, and thereby eliminating cases of implicit copying.  Furthermore, even in an assignment statement, it is not always clear that you would want to do a deep copy when such a
n access object is assigned to another.  It depends heavily on the context.  For example, if you wanted to create a pointer that was to walk over an existing tree structure, you certainly wouldn't want the creation of that temporary pointer to result in th
e creation of a copy of the tree.  This leads us to define the four kinds of ownership-based access subtypes mentioned above, and also to define some attributes to be used for specifying explicitly how the copying of an acces
-object is to be performed.
-
-The first case to consider is a "simple" assignment from an owner access object to another owner access object.  There are two interesting
-alternatives:
+The first case to consider is a "simple" assignment from an owner access object
+to another owner access object.  There are two interesting alternatives:
   1) Assign a deep copy of the RHS into the LHS; or
   2) Move the ownership from the RHS to the LHS, and null-out the RHS.
 
-In both cases, if the LHS already designated an object, we would want to finalize and reclaim the storage for that object before overwriting the LHS.  (Alternatively, we could require that the LHS be null before the assignment, forcing the user to explici
tly set it to null first.)
+In both cases, if the LHS already designated an object, we would want to
+finalize and reclaim the storage for that object before overwriting the LHS.
+(Alternatively, we could require that the LHS be null before the assignment,
+forcing the user to explicitly set it to null first.)
 
-To distinguish these two cases we propose the use of an explicit attribute, either 'Copy or 'Move:
+To distinguish these two cases we propose the use of an explicit attribute,
+either 'Copy or 'Move:
   1) LHS := RHS'Copy;  --  Deep copy
-  2) LHS := RHS'Move;  --  Move; set RHS to null We don't think there is a safe, obvious default, so we propose that the attribute is required.  Simple assignment from one owner object to another would not be permitted without specifying such an attribute
.
-Either 'Copy or 'Move must also be used when initializing an owner component of an aggregate as a copy of another owner object, or when returning an owner object from a function.  An allocator could be thought of as a short-lived owner object, from which 
'Move semantics is implicit. Any owner object that is non-null when it is finalized will be effectively set to null, causing finalization and reclamation of its designated object.
-
-The next case to consider is when you want to create a temporary pointer to "walk" a data structure, either with read/write or read-only access.
-Here we introduce the notion of a "borrower" and an "observer."  A "borrower" is an access object that provides read/write access to the designated object, and recursively has read/write access to the whole object "tree" through owner subcomponents of the
 designated object.  An "observer" is an access object that provides read-only access to the designated object, and recursively has read-only access through owner subcomponents of the designated object to the object tree.
+  2) LHS := RHS'Move;  --  Move; set RHS to null
 
-To create such a temporary pointer via an assignment, we require that the LHS be declared as part of the assignment, that it be of the appropriate Access_Kind (Borrower or Observer), and that an attribute ('Borrow or 'Observe) is used on the RHS to indica
te what sort of operation is being performed.  Hence:
+We don't think there is a safe, obvious default, so we propose that the
+attribute is required.  Simple assignment from one owner object to another would
+not be permitted without specifying such an attribute.
+
+Either 'Copy or 'Move must also be used when initializing an owner component of
+an aggregate as a copy of another owner object, or when returning an owner
+object from a function.  An allocator could be thought of as a short-lived owner
+object, from which 'Move semantics is implicit. Any owner object that is
+non-null when it is finalized will be effectively set to null, causing
+finalization and reclamation of its designated object.
+
+The next case to consider is when you want to create a temporary pointer to
+"walk" a data structure, either with read/write or read-only access. Here we
+introduce the notion of a "borrower" and an "observer."  A "borrower" is an
+access object that provides read/write access to the designated object, and
+recursively has read/write access to the whole object "tree" through owner
+subcomponents of the designated object.  An "observer" is an access object that
+provides read-only access to the designated object, and recursively has
+read-only access through owner subcomponents of the designated object to the
+object tree.
+
+To create such a temporary pointer via an assignment, we require that the LHS be
+declared as part of the assignment, that it be of the appropriate Access_Kind
+(Borrower or Observer), and that an attribute ('Borrow or 'Observe) is used on
+the RHS to indicate what sort of operation is being performed.  Hence:
 
   1) LHS : Acc_T with Access_Kind => Borrower := RHS'Borrow;
            --  create a borrower; RHS must be owner or borrower
   2) LHS : Acc_T with Access_Kind => Observer := RHS'Observe;
            --  create an observer; RHS may be owner, borrower, or observer
-
-We could relax the requirement for specifying the 'Borrow or 'Observe attribute in cases where only one would be permitted based on the subtype of the LHS, but we believe it should be possible to be explicit if desired.
-
-To provide a modicum of safety, during the scope of a borrower, the RHS from which it originated is frozen, and cannot be dereferenced or changed. Similarly, during the scope of an observer, the RHS and any borrowers derived from it also effectively becom
e observers, providing only read access to the object tree.
-
-An observer object may be assigned a new value after its declaration, but only if the RHS of the assignment is another observer that is declared in the same or an outer scope, or is an owner component that is in the object "tree" rooted at the object desi
gnated by such an observer. In other words, observers can walk "down" an object tree, or jump over to another object tree that is being observed at least as long as the tree the observer is associated with.
-
-Similarly, a borrower object may be assigned a new value if the RHS is an owner component within the object tree rooted at the object currently designated by the borrower.  This means a borrower can also walk down its object tree.  Unlike an observer, it 
is not permitted to "jump" to some other tree.
-
-Formal parameters of an ownership-based access type are treated specially -- their Access_Kind has a default.  An IN-OUT or OUT parameter of an ownership-based access type is treated as Access_Kind Owner.  An IN parameter is by default treated as Access_K
ind Borrower, but this can be overridden by using a formal parameter subtype with Access_Kind Observer.  As implied by the Access_Kind of an [IN] OUT parameter being Owner, passing an owner object to an [IN] OUT parameter automatically uses "'Move" semanti
cs, both ways, meaning that the actual is set to null during the execution of the subprogram.  This allows the formal parameter to be assigned a new value, including null, with the appropriate semantics.  For an IN parameter, "'Borrow" or "'Observe"
-semantics, are used as determined by the Access_Kind of the formal. An [IN] OUT formal parameter needs to be set to null implicitly when a subprogram ends abnormally (due to propagating an exception or being aborted), to avoid storage leakage.
 
-An access object of an ownership-based access type can be passed to a subprogram with an access parameter (i.e. a formal parameter of an anonymous access type) only if the subprogram as a whole has its Ownership aspect specified as True.  In that case, an
 access-to-variable parameter automatically has Access_Kind Borrower, and an access-to-constant parameter automatically has Access_Kind Observer.
-Similarly, the result type may be of an anonymous access type (i.e., an "access result"), and the Access_Kind is Borrower or Observer according to whether it is access-to-variable or access-to-constant.
+We could relax the requirement for specifying the 'Borrow or 'Observe attribute
+in cases where only one would be permitted based on the subtype of the LHS, but
+we believe it should be possible to be explicit if desired.
+
+To provide a modicum of safety, during the scope of a borrower, the RHS from
+which it originated is frozen, and cannot be dereferenced or changed. Similarly,
+during the scope of an observer, the RHS and any borrowers derived from it also
+effectively become observers, providing only read access to the object tree.
+
+An observer object may be assigned a new value after its declaration, but only
+if the RHS of the assignment is another observer that is declared in the same or
+an outer scope, or is an owner component that is in the object "tree" rooted at
+the object designated by such an observer. In other words, observers can walk
+"down" an object tree, or jump over to another object tree that is being
+observed at least as long as the tree the observer is associated with.
+
+Similarly, a borrower object may be assigned a new value if the RHS is an owner
+component within the object tree rooted at the object currently designated by
+the borrower.  This means a borrower can also walk down its object tree.  Unlike
+an observer, it is not permitted to "jump" to some other tree.
+
+Formal parameters of an ownership-based access type are treated specially --
+their Access_Kind has a default.  An IN-OUT or OUT parameter of an
+ownership-based access type is treated as Access_Kind Owner.  An IN parameter is
+by default treated as Access_Kind Borrower, but this can be overridden by using
+a formal parameter subtype with Access_Kind Observer.  As implied by the
+Access_Kind of an [IN] OUT parameter being Owner, passing an owner object to an
+[IN] OUT parameter automatically uses "'Move" semantics, both ways, meaning that
+the actual is set to null during the execution of the subprogram.  This allows
+the formal parameter to be assigned a new value, including null, with the
+appropriate semantics.  For an IN parameter, "'Borrow" or "'Observe" semantics,
+are used as determined by the Access_Kind of the formal. An [IN] OUT formal
+parameter needs to be set to null implicitly when a subprogram ends abnormally
+(due to propagating an exception or being aborted), to avoid storage leakage.
+
+An access object of an ownership-based access type can be passed to a subprogram
+with an access parameter (i.e. a formal parameter of an anonymous access type)
+only if the subprogram as a whole has its Ownership aspect specified as True.
+In that case, an access-to-variable parameter automatically has Access_Kind
+Borrower, and an access-to-constant parameter automatically has Access_Kind
+Observer. Similarly, the result type may be of an anonymous access type (i.e.,
+an "access result"), and the Access_Kind is Borrower or Observer according to
+whether it is access-to-variable or access-to-constant.
+
+The 'Borrow and 'Observe attributes can be used on function return, but only if
+the prefix of the attribute reference is derived from a formal parameter that is
+of the corresponding Access_Kind, and the result subtype has the corresponding
+Access_Kind.  Such a function is called a "traversal function," in that it is
+used to traverse down an object tree, returning an observer or borrower
+reference to a point somewhere within the tree.  Such traversal functions could
+be used to search within a tree, or just do some sort of systematic walk down
+the tree.
+
+Passing a composite object that has an owner access object as a subcomponent
+implicitly observes or borrows that owner object, depending on whether it is
+passed as an IN parameter, or as an [IN] OUT parameter, respectively. This is
+only of concern in places where the caller has visibility on the components.
+Presuming the composite type is a private type, no special rules would apply
+where this partial view is all that is visible, because the objects designated
+by the owner objects are effectively treated like any other non-visible
+subcomponent of the composite object.
+
+A component of a composite type is not permitted to be of a Borrower or Observer
+subtype.  Borrowers or observers can only be stand-alone objects or formal
+parameters.  On the other hand, components can be of Access_Kind Owner or
+Unmanaged.  Owner objects are described above. Unmanaged objects are intended
+for use as back pointers, cursors, or other sorts of secondary references.
+
+To lessen the possibility of misuse of unmanaged access objects, we do not allow
+them to be directly dereferenced.  Instead, they must be used to initialize an
+observer or borrower, using an 'Observe or 'Borrow attribute, but where the
+attribute has an operand that identifies the unmanaged object whose value is to
+be used, but is protected by the object that is being observed or borrowed. By
+"protecting" we mean that the protector is an owner, or derived from an owner
+access object that owns, directly or indirectly, the object designated by the
+unmanaged access object.  This ensures that the unmanaged access object is not
+pointing off into thin air. For example, here is a possible implementation of a
+Hashed_Map using ownership-based access types, and using two unmanaged access
+objects to implement a cursor:
 
-The 'Borrow and 'Observe attributes can be used on function return, but only if the prefix of the attribute reference is derived from a formal parameter that is of the corresponding Access_Kind, and the result subtype has the corresponding Access_Kind.  S
uch a function is called a "traversal function," in that it is used to traverse down an object tree, returning an observer or borrower reference to a point somewhere within the tree.  Such traversal functions could be used to search within a tree, or just 
do some sort of systematic walk down the tree.
-
-Passing a composite object that has an owner access object as a subcomponent implicitly observes or borrows that owner object, depending on whether it is passed as an IN parameter, or as an [IN] OUT parameter, respectively. This is only of concern in plac
es where the caller has visibility on the components.  Presuming the composite type is a private type, no special rules would apply where this partial view is all that is visible, because the objects designated by the owner objects are effectively treated 
like any other non-visible subcomponent of the composite object.
-
-A component of a composite type is not permitted to be of a Borrower or Observer subtype.  Borrowers or observers can only be stand-alone objects or formal parameters.  On the other hand, components can be of Access_Kind Owner or Unmanaged.  Owner objects
 are described above.
-Unmanaged objects are intended for use as back pointers, cursors, or other sorts of secondary references.
-
-To lessen the possibility of misuse of unmanaged access objects, we do not allow them to be directly dereferenced.  Instead, they must be used to initialize an observer or borrower, using an 'Observe or 'Borrow attribute, but where the attribute has an op
erand that identifies the unmanaged object whose value is to be used, but is protected by the object that is being observed or borrowed. By "protecting" we mean that the protector is an owner, or derived from an owner access object that owns, directly or i
ndirectly, the object designated by the unmanaged access object.  This ensures that the unmanaged access object is not pointing off into thin air. For example, here is a possible implementation of a Hashed_Map using ownership-based access types, and using 
two unmanaged access objects to implement a cursor:
-
    function Element (Container : Map;
                      Position : Cursor)
       return Element_Type
@@ -123,19 +259,30 @@
       return Node.Element;
    end Element;
 
-Unmanaged access objects can be created by copying an object of any other Access_Kind, by applying the 'Unmanaged attribute.  E.g.:
+Unmanaged access objects can be created by copying an object of any other
+Access_Kind, by applying the 'Unmanaged attribute.  E.g.:
 
     Position := Cursor'(Backbone => Map.Backbone'Unmanaged,
                         Node => Some_Node'Unmanaged);
 
-We could relax the requirement to use 'Unmanaged on creation of such a value if the target is of Access_Kind Unmanaged, but it seems helpful to allow an explicit use of the attribute.
+We could relax the requirement to use 'Unmanaged on creation of such a value if
+the target is of Access_Kind Unmanaged, but it seems helpful to allow an
+explicit use of the attribute.
 
 It is erroneous to use an unmanaged access object as the operand of
-<prefix>'Borrow(...) or <prefix>'Observe(...) if it does not designate an object within the object tree designated by the prefix.
+<prefix>'Borrow(...) or <prefix>'Observe(...) if it does not designate an object
+within the object tree designated by the prefix.
 
-For operations that need to dereference an unmanaged access object, but do not have a formal parameter that can be used as the "protector" of the unmanaged object, we provide 'Unchecked_Borrow and 'Unchecked_Observe which can be applied to an unmanaged ob
ject to produce a borrower or an observer.  It is erroneous to use such an attribute if the designated object no longer exists, or if some dynamically enclosing caller of the operation does not have an access object with corresponding access to the object,
 directly or indirectly.
-Also, such an operation must have a Global aspect that indicates "access T" or "<package_name>" because there is no formal parameter that can
-"carry" the side effects of the operation.   For example:
+For operations that need to dereference an unmanaged access object, but do not
+have a formal parameter that can be used as the "protector" of the unmanaged
+object, we provide 'Unchecked_Borrow and 'Unchecked_Observe which can be applied
+to an unmanaged object to produce a borrower or an observer.  It is erroneous to
+use such an attribute if the designated object no longer exists, or if some
+dynamically enclosing caller of the operation does not have an access object
+with corresponding access to the object, directly or indirectly. Also, such an
+operation must have a Global aspect that indicates "access T" or
+"<package_name>" because there is no formal parameter that can "carry" the side
+effects of the operation.   For example:
 
    function Element (Position : Cursor)
         return Element_Type
@@ -154,30 +301,70 @@
 TBD
 
 !discussion
-
-See !problem and !proposal for much of the rationale for what we propose. Here we will try to provide a rationale for what we chose *not* to do.
-
-We have required the explicit use of 'Move or 'Copy on owner-object assignments.  We originally had proposed that "move" semantics were the default, but we have come to feel that that is too error prone and potentially confusing.  Also, "move" semantics h
ave a side-effect of nulling out the RHS, but that is quite different from how normal assignments work, including that it requires the RHS to be a variable.
 
-We have made deep copy implicit in assignments of composite objects containing owner objects.  We originally had "move" semantics here as well, but it was pointed out that this had real problems in the context of controlled types, because if the user want
ed to implement deep copy on their own using Adjust, it would sort of be "too late" since either the RHS has already had nulls written all over it, or if we suppress that, we pass an object to Adjust that we want to do deep copy "in place" but any attempt 
to assign a new value to an owner component would immediately reclaim the old value.  All in all a bit of a mess.  By instead making deep copy implicit for composite objects containing owner objects (even if they are controlled), Adjust can be used merely 
to do any other operations that are needed beyond this deep copying.
+See !problem and !proposal for much of the rationale for what we propose. Here
+we will try to provide a rationale for what we chose *not* to do.
 
-More generally, we had some complex rules relating to composite objects with Ownership True.  We have eliminated all of those.  The implicit deep copy effectively allows a tree of objects to be treated as a "flat"
-object, without much of any further special concerns.
+We have required the explicit use of 'Move or 'Copy on owner-object assignments.
+We originally had proposed that "move" semantics were the default, but we have
+come to feel that that is too error prone and potentially confusing.  Also,
+"move" semantics have a side-effect of nulling out the RHS, but that is quite
+different from how normal assignments work, including that it requires the RHS
+to be a variable.
+
+We have made deep copy implicit in assignments of composite objects containing
+owner objects.  We originally had "move" semantics here as well, but it was
+pointed out that this had real problems in the context of controlled types,
+because if the user wanted to implement deep copy on their own using Adjust, it
+would sort of be "too late" since either the RHS has already had nulls written
+all over it, or if we suppress that, we pass an object to Adjust that we want to
+do deep copy "in place" but any attempt to assign a new value to an owner
+component would immediately reclaim the old value.  All in all a bit of a mess.
+By instead making deep copy implicit for composite objects containing owner
+objects (even if they are controlled), Adjust can be used merely to do any other
+operations that are needed beyond this deep copying.
+
+More generally, we had some complex rules relating to composite objects with
+Ownership True.  We have eliminated all of those.  The implicit deep copy
+effectively allows a tree of objects to be treated as a "flat" object, without
+much of any further special concerns.
+
+We considered requiring that these ownership-based access types be declared in a
+private part, but that doesn't really accomplish much given that you can define
+a private child with full visibility on the private part of its parent.
+
+We considered requiring that an ownership-based access type identify all of the
+externally visible composite types where it was allowed to be used as a
+component.  But that smacks of the "come from" approach to control flow, and
+creates annoying maintenance headaches. The main use for this list of
+composite-type "users" was to have reasonable semantics for the use of unmanaged
+access objects.  But now that we disallow direct dereferencing of unmanaged
+objects, and provide various attributes to convert them to observers or
+borrowers, we believe there is no need to identify the composite types where
+owner components are permitted.
+
+We considered requiring composite types with owner components be by-reference
+types due to being tagged or immutably limited, but instead we concluded that it
+is simpler to just say that having an owner access object as a subcomponent
+should by itself cause a type to be by-reference.  We already do this with
+volatile subcomponents, so it seems simple enough to have owner subcomponents
+have the same effect.
+
+We went round and round on names.  We settled here on "ownership-based" access
+types.  We considered: owning, owner, owned, fenced, controlled, managed, etc.
+We like "ownership-based" because it acknowledges that we are using pointer
+ownership principles, but that not every object is an "owning" object.  In the
+programming-language world, "managed" has come to mean "using garbage
+collection" which seems misleading.  "Controlled" is an option, except we would
+then have to have "controlled access types" and "controlled tagged types" which
+would mean quite a few changes in the manual (and perhaps in our brains).  Also,
+there was an pragma Controlled defined up until Ada 2005 on access types, which
+means something rather different.
 
-We considered requiring that these ownership-based access types be declared in a private part, but that doesn't really accomplish much given that you can define a private child with full visibility on the private part of its parent.
-
-We considered requiring that an ownership-based access type identify all of the externally visible composite types where it was allowed to be used as a component.  But that smacks of the "come from" approach to control flow, and creates annoying maintenan
ce headaches. The main use for this list of composite-type "users" was to have reasonable semantics for the use of unmanaged access objects.  But now that we disallow direct dereferencing of unmanaged objects, and provide various attributes to convert them
 to observers or borrowers, we believe there is no need to identify the composite types where owner components are permitted.
-
-We considered requiring composite types with owner components be by-reference types due to being tagged or immutably limited, but instead we concluded that it is simpler to just say that having an owner access object as a subcomponent should by itself cau
se a type to be by-reference.  We already do this with volatile subcomponents, so it seems simple enough to have owner subcomponents have the same effect.
-
-We went round and round on names.  We settled here on "ownership-based"
-access types.  We considered: owning, owner, owned, fenced, controlled, managed, etc.  We like "ownership-based" because it acknowledges that we are using pointer ownership principles, but that not every object is an "owning" object.  In the programming-l
anguage world, "managed" has come to mean "using garbage collection" which seems misleading.  "Controlled"
-is an option, except we would then have to have "controlled access types" and "controlled tagged types" which would mean quite a few changes in the manual (and perhaps in our brains).  Also, there was an pragma Controlled defined up until Ada 2005 on acce
ss types, which means something rather different.
-
 !example
-
-For a linked list container, we might have declarations like the following in the private part:
 
+For a linked list container, we might have declarations like the following in
+the private part:
 
      type Node;
      type Node_Ptr is access Node
@@ -195,26 +382,34 @@
 
 (Note: List is the visible private type.)
 
-The Prev component is NOT an owner object; it is used only for list traversal and does not have any effect on the lifetime of the objects.
+The Prev component is NOT an owner object; it is used only for list traversal
+and does not have any effect on the lifetime of the objects.
 
-If the implementation wanted to have a free list of nodes, it could declare the following (probably in a protected object):
+If the implementation wanted to have a free list of nodes, it could declare the
+following (probably in a protected object):
 
    Free_List : Node_Ptr with Access_Kind => Owner := null;
 
-Then moving a Node_Ptr to this object would have the effect of changing the owner to the global protected object (dereferencing such a pointer would require Global to include this protected object).
+Then moving a Node_Ptr to this object would have the effect of changing the
+owner to the global protected object (dereferencing such a pointer would require
+Global to include this protected object).
 
 !ASIS
 
-[Not sure. It seems like some new capabilities might be needed, but I didn't check - Editor.]
+[Not sure. It seems like some new capabilities might be needed, but I didn't
+check - Editor.]
 
 !ACATS test
 
-ACATS B- and C-Tests are needed to check that the new capabilities are supported.
+ACATS B- and C-Tests are needed to check that the new capabilities are
+supported.
 
 
 !appendix
 
-[Editor's note: This private conversation is being posted here in case anyone is interested in fleshing out this proposal. It was abandoned due to lack of time rather than any technical problems.]
+[Editor's note: This private conversation is being posted here in case anyone is
+interested in fleshing out this proposal. It was abandoned due to lack of time
+rather than any technical problems.]
 
 From: Tucker Taft
 Sent: Thursday, December 20, 2018  2:29 PM

Questions? Ask the ACAA Technical Agent