CVS difference for ai05s/ai05-0138-1.txt

Differences between 1.1 and version 1.2
Log of other versions for file ai05s/ai05-0138-1.txt

--- ai05s/ai05-0138-1.txt	2009/02/14 06:40:41	1.1
+++ ai05s/ai05-0138-1.txt	2009/02/18 05:47:51	1.2
@@ -4454,3 +4454,707 @@
 decided it wasn't worth trying to figure out how to make it work.
 
 ****************************************************************
+
+From: Bob Duff
+Sent: Sunday, February 15, 2009  12:06 PM
+
+> P.S. You may want to read this with your favorite adult beverage. It's 
+> not light reading.
+> I surely am going to go have an adult beverage now... ;-)
+
+I assume you mean coffee.
+
+> !problem
+> 
+> Accessibility of access types and that of their designated objects 
+> never seems to be quite what is needed for an application. Many 
+> projects simply use 'Unchecked_Access exclusively, because the 
+> accessibility checks do nothing other than get in the way.
+> Moreover, we have a hodge-podge of default rules for anonymous access types:
+> we
+> have different rules for access discriminants, access parameters, 
+> access results, and other anonymous access types. And some of these 
+> rules require run-time overhead.
+
+> accessibility_clause ::= with *accessibility_static_string_*expression
+> 
+> This would look something like:
+> 
+>     Param : access My_Type with "call-level accessibility";
+> 
+> [Notes: I'm using a static string here because I don't want to define 
+> a mess of reserved words, and I don't want to add a type to Standard 
+> for this. The latter idea was to add an enumeration Accessibility_Type 
+> to Standard and use that in an accessibility clause:
+
+I find the use of string literals in the proposed syntax to be rather ugly.
+You could add Accessibility_Type somewhere less intrusive than Standard
+-- just invent a new package.
+
+> accessibility_clause ::= with *accessibility_*expression [of 
+> *entity_*name]
+> 
+> That would look something like:
+> 
+>     Param : access My_Type with call_level_accessibility;
+> 
+> The need for the extra entity clause makes this less appealing. Of 
+> course, if we were to drop that capability, it becomes more 
+> interesting.]
+> 
+> If no accessibility clause is given, the rules would remain as they 
+> are now (thus, this proposal has no compatibility issues).
+> 
+> The following static strings are allowed as
+> "accessibility_static_string_expression"s:
+> 
+> "library-level accessibility"
+>    The accessibility of the designated objects of the access type is 
+> library-level.
+>    Conversions into the type are statically checked to be 
+> library-level; this follows
+>    the current model of accessibility checking in Ada (note that in a 
+> few cases, such
+>    checks are actually dynamic). Note that whenever we talk about 
+> "converting to an
+>    access type" we're also talking about 'Access and the checks on the 
+> object prefix
+>    of the attribute; the checks are essentially the same. We'll only 
+> talk about
+>    converting to a type in order to simplify the presentation.
+> 
+> "current accessibility"
+>    The accessibility of the designated objects of the access type is 
+> that of the
+>    location of the declaration. This is the default for all named 
+> access types
+>    and many kinds of anonymous access types, and corresponds to the 
+> current rules for
+>    those cases. Accessibility checks for conversions into the type are 
+> statically
+>    checked.
+
+The default accessibility level for an anonymous access type should be the
+level of the designated subtype (normally library level).  This is a key
+mistake in the current design.
+
+> "accessibility of <entity-name>"
+>    Entity-name must statically denote an entity that is visible at the 
+> point of the
+>    access declaration. The entity must be a subprogram, stand-alone 
+> object, or type.
+>    The accessibility of the designated objects is that of the 
+> specified entity (for
+>    an access type, if it has an accessibility_clause that is used).
+> Accessibility
+>    checks for conversions into the type are statically checked.  This 
+> allows the
+>    definition of any arbitrary static accessibility level, so long as 
+> it is shallower
+>    than the current point.
+>    [Note: I really wanted this to just match any existing access type, 
+> so <entity-name>
+>    could just be the name of an access type. However, since we have 
+> those dang anonymous
+>    access types, we have to allow other entities like subprograms and 
+> objects here.]
+
+You could use "acessibility of Standard" instead of "library-level accessibility".
+You could use "acessibility of X" to mean "current accessibility", for a suitably
+placed X.
+
+And then use syntax like:
+
+accessibility_clause ::= at name
+
+In other words, if there's always a name that means what you want to mean, we don't
+need the string literal syntax.
+
+> "and no pool" may be added to any of the above accessibility strings. 
+> This means the same as specifying Storage_Size to be 0 (that can't be 
+> done explicitly for anonymous access types) -- specifically, 
+> allocators are illegal for the type. This should have been the default 
+> for anonymous access types, but it is too late to change that now.
+
+Sounds useful.
+
+It should have been the default for ALL access types, but it's WAY too late for that
+now.
+
+You could say that if there's an accessibility_clause, it implies "no pool".
+
+> !discussion
+> 
+> I think that in new code, all access types should specify their 
+> intended accessibility.
+> That would eliminate confusion about what it the accessibility is and 
+> avoid incorrect assumptions about capability. That is especially true 
+> for anonymous access types where there are many different kinds of 
+> accessibility chosen by default (and
+> AI05-0051-1
+> would add another, and Tucker wants to add another for objects). That 
+> does suggest that a simpler syntax would be preferable; I'll leave 
+> that to others.
+
+The syntax sure is getting verbose:
+
+    procedure Mumble (X : not null access constant My_Type with "library-level
+                      accessibility" and no pool);
+
+Almost entirely specifying stuff that should have been the default.
+
+The C programmer who says "char *x" is going to laugh at us.
+
+> Detailed discussion of call-level accessibility:
+> 
+> For an anonymous access parameter, call-level accessibility means the 
+> accessibility of the parameters of the call. (We modify this 
+> accessibility in certain cases for functions with anonymous access 
+> results, see below.) This requires no checking at the point of call; 
+> any object that exists at the point of the call will necessarily live 
+> long enough. An allocator of such a parameter (if allowed) would have 
+> the accessibility of the point of the call (this is unchanged from Ada 
+> 95/2005 other than in cases with anonymous access results).
+
+I'm not sure I see the point of call-level accessibility.  Why not use an 'in out'
+parameter?  (Presuming AI05-0143-1 is approved -- it's titled "It's BAAACCKK!!:
+In Out parameters for functions".)
+
+Maybe it's for access results, which I do not understand.
+
+> Converting an anonymous access parameter with call-level accessibility 
+> to another access type (recall that we are including 'Access when we 
+> say "convert to an access
+> type") triggers
+> an appropriate accessibility check (of course, the type of check 
+> depends on the accessibility of the target type). If the target type 
+> is has some form of static accessibility (other than call-level 
+> accessibility, we'll cover that below), we'll need a static 
+> accessibility check (along with a dynamic check as in existing Ada). 
+> The check will succeed if the access type is local to the subprogram 
+> (or a nested subprogram) and fail otherwise. This can almost always be 
+> checked statically (I can't think of a case where it cannot, as a 
+> generic formal access type would necessarily be outside of the 
+> subprogram and thus would fail the check). When making these checks, 
+> we don't assume anything about the call site, so we don't allow 
+> converting to any type with a longer life than the call, which is 
+> anything visible outside of the subprogram call.
+> 
+> One can imagine that call-level accessibility is essentially a static 
+> level half-way in between the level of the current subprogram and 
+> whatever the outer level is. It could even be implemented that way if 
+> it was passed to an anonymous access parameter with dynamic 
+> accessibility. (Since the number of nesting levels is small, there 
+> should be plenty of bits available to represent half-levels.)
+
+type Accessibility_Level is delta 0.5 range 0.0 .. Max; for
+   Accessibility_Level'Small use Accessibility_Level'Delta;
+
+;-)
+
+My overall impression: Some good ideas, but way too complicated to implement
+(as is -- maybe it can be simplified, but I don't understand the details
+well enough to know).
+
+All this accessibility level stuff is to prevent dangling pointers being
+created by '[Unchecked_]Access.  But the primary use of access types is to
+create heap-allocated data structures.  In fact, that's all we had in Ada 83,
+and we got along OK.  So the primary way of creating dangling pointer bugs is
+to call Unchecked_Deallocation prematurely.  Makes me think we are inventing
+large amounts of stuff that completely misses the point.
+
+Keep in mind that we could also implement garbage collection.  (There's an open
+ticket at AdaCore to do so.)  If we keep complicating the accessibility rules,
+implementing a GC starts looking "simple".  I realize, of course, that there
+are some embedded applications that are allergic to GC.  But for other
+applications, it sure would be nice to remove one of the major advantages of
+Java and C# over Ada.  I'd rather spend my time implementing GC than
+implementing arcane dynamic accessibility checks.  (OK, I admit I'm exaggerating
+-- an efficient GC is a LOT of work.)
+
+****************************************************************
+========= End of thread ==========
+== New thread: Comments on the AI (everything mixed together) ===
+****************************************************************
+
+From: Bob Duff
+Sent: Sunday, February 15, 2009  7:20 AM
+
+This is a comment (a rant, really ;-) ) primarily on AI05-0138, "Improving
+accessibility", but I think there are several related AI's.
+
+I think anonymous access types were a mistake in Ada 95, and a bigger mistake
+in Ada 2005.  I am concerned that the ARG will add a whole new set of
+complicated rules for Ada 201X, causing a whole lot of implementation
+complexity for no real user benefit.
+
+Franco proposed the 'Ref idea (see first e-mail in the appendix).
+It lists seven problems with anonymous access types.  I've listed some more
+problems below.
+
+Tucker proposed dynamic accessibility for local anonymous access variables,
+which largely solves _one_ of the problems.  But it seems to me if we're not
+going to solve all or nearly all of the problems, we should give up.
+(I'm also concerned about efficiency.  It sounds easy enough to optimize
+away most dynamic accessibility, in principle, but I fear compilers might not
+have the right information at the time they are doing the necessary flow
+analysis.  I'm not sure whether GNAT would do it in the front end, or in gigi.)
+
+I think it is impossible to solve all the problems without serious incompatibility.
+If I'm proven wrong, that's great. But adding a lot of complexity is not a
+solution -- part of the problem is that we have too much already, in this area.
+
+I think Franco's proposal fixes nearly all of the problems, and is reasonably
+simple.  AdaCore might go ahead and implement it as an experiment -- it's
+based on an attribute, so it's an allowable implementation-defined extension.
+
+We could try to fix anonymous access types.
+Or we could go with Franco's proposal.
+But at this point, I think perhaps the best solution is to do nothing --
+Ada really doesn't need a whole new layer of complexity!
+
+Let's not repeat the mistake, making anonymous access types more usable, but
+still not usable enough to be worth the trouble.
+
+----------------
+
+Problems in addition to the ones Franco mentioned:
+
+Using anonymous access types does not allow you to eliminate named access types --
+you still need to declare a named access type for every interesting type (where
+"interesting" = "you want to put some objects of that type in the heap").
+
+Anonymous access types do not eliminate the need for bogus explicit type
+conversions; conversion that can't fail (up the tagged type hierarchy) should be
+implicit. I suppose you can use .all'Access, but that's kind of ugly.
+
+The above two items were the main purpose of introducing anonymous access types
+all over the place in Ada 2005, but they don't work.
+
+I think anonymous access types are fundamentally confusing, because (for
+parameters and discriminants, and perhaps function results) they have various
+special properties.  It's just confusing that "X: access T"
+means something different from "X: Access_T".  Doubly so, because the special
+properties are different depending on what X is.
+
+Access parameters have dynamic accessibility, which is never what you want.
+It's just a tripping hazard, and it breaks abstraction. Also, we violate the
+normal principle that if you're going to have a run-time check, there ought
+to be some way to check it explicitly with an 'if' statement, as in "if X in
+A'Range then A(X) := A(X) + 1; else...".
+
+The accessibility rules are confusing.  When people say "new T", they expect
+it to allocate an object in a global heap, to be explicitly reclaimed later.
+But in some cases, the object gets automatically reclaimed (and finalized) early.
+This is just not what people expect of "new".  It can easily cause accidental
+creation of dangling pointers.  (Tucker points out that this malfeature existed
+in Ada 95, so people are used to it. But it's only for parameters in Ada 95,
+and you don't normally pass "new T" as an actual parameter.  The issue is much
+more common in Ada 2005, and still just as confusing.)  (Actually, I now see
+it's even worse than I thought -- the time of automatic deallocation, if any,
+is not portable!)
+
+There's some discussion about what "return access T" means, with the possible
+introduction of yet more confusing and complex accessibility rules.  I've no
+idea what this feature means, so I'm afraid to use it myself.
+
+Coextensions have some cool properties, but the number of Ada programmers in
+the world who understand them well enough to actually make use of them can be
+counted on the fingers of one hand.
+
+(This one is not specifically about anonymous types.)  If you say "new" for
+one access type, convert to another type, and then Unchecked_Deallocate from
+the other type, it is implementation dependent whether this is erroneous.
+In most compilers, it works just fine, and in fact people do it all the time.
+To me, this is just an unacceptable non-portability.
+
+----------------
+
+Randy is fond of pointing out that access types should always be hidden, and 
+therefore it doesn't matter if they're a pain in the neck.  I don't agree with
+that view -- in my opinion, if your abstraction involves reference semantics,
+hiding that fact is confusing.  Anyway, I'm not trying to convince Randy that
+he's wrong -- Randy can hide his access types if he likes.  I'm just trying to
+point out that Randy's point of view is a minority one, so it would be wrong
+to base the language design on that narrow view.
+
+Nor do I buy Randy's argument that Ada.Containers can replace nearly all access
+types.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Monday, February 16, 2009  8:22 PM
+
+...
+> Problems in addition to the ones Franco mentioned:
+> 
+> Using anonymous access types does not allow you to eliminate named 
+> access types -- you still need to declare a named access type for 
+> every interesting type (where "interesting" = "you want to put some 
+> objects of that type in the heap").
+> 
+> Anonymous access types do not eliminate the need for bogus explicit 
+> type conversions; conversion that can't fail (up the tagged type 
+> hierarchy) should be implicit.
+> I suppose you can use .all'Access, but that's kind of ugly.
+> 
+> The above two items were the main purpose of introducing anonymous 
+> access types all over the place in Ada 2005, but they don't work.
+
+Yes, I agree. I especially worry that when we (the ARG) said that the
+anonymous access was getting too complex, they were simplified. But now
+it turns out that those simplifications don't work, so now we're supposed
+to swallow the entire original mess. I would have voted to remove it had
+I had any idea that those simplifications (especially for function results)
+were not going to work.
+
+...
+> Randy is fond of pointing out that access types should always be 
+> hidden, and therefore it doesn't matter if they're a pain in the neck.  
+> I don't agree with that view -- in my opinion, if your abstraction 
+> involves reference semantics, hiding that fact is confusing.
+
+I don't believe that any abstraction fundementally involves reference semantics
+(which is just a artifact of programming languages anyway). If it appears
+to do so, it probably is not well designed.
+
+> Anyway, I'm not trying to convince Randy that he's wrong -- Randy can 
+> hide his access types if he likes.  I'm just trying to point out that 
+> Randy's point of view is a minority one, so it would be wrong to base 
+> the language design on that narrow view.
+
+I would not argue that point, however.
+
+> Nor do I buy Randy's argument that Ada.Containers can replace nearly 
+> all access types.
+
+The only time where Ada.Containers (with extensions) would not be appropriate
+is when the performance of those containers is insufficient for the
+application. (That should be a rare occurrence.) In that case, you might
+need to use access types and some kind of hand-built storage mechanism. But
+if that is the case, you surely don't want dynamic anything on those access
+types, so the anonymous access types we currently have are almost certainly
+not helping anything. (This is the same reason that I'm dubious about the
+value of garbage collection in Ada - if you're writing a lot of code that
+needs it, you are doing something wrong.)
+
+The only other reason to avoid using the containers is because they are
+hard to use in some application. That we can fix, and indeed most of my
+emphasis has been on adding missing functionality to the containers and
+to the language to make the containers easier to use. (If it helps make
+other abstractions easier to use, that's even better.)
+
+If you know of some other reason for using access types rather than
+containers that are not covered by one of these two, I'd surely like
+to know what it is so it can be addressed in *this* cycle.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Monday, February 16, 2009  11:01 PM
+
+...
+> Randy is fond of pointing out that access types should always be 
+> hidden, and therefore it doesn't matter if they're a pain in the neck.
+
+I forgot to respond to this statement in my previous mail.
+
+I don't recall ever saying that "it doesn't matter if access types are
+a pain the neck". I think named access types work just fine, and could
+be even better with some pool enhancements. Anonymous access types
+don't buy anything that named ones don't, except a few less type
+conversions. They isn't worth the accessibility mess. Of course, if your
+access types are hidden, you don't need to write any type conversions
+for them, so named access types are just fine.
+
+Of course, looking at it another way, access types are a pain in the neck
+simply because dynamic allocation and deallocation lead to all kinds of
+problems. Short of mandating garbage collection, that pain isn't going
+anywhere. But at least hiding them as much as possible, and using
+containers as much as possible, reduces the pain to managable levels.
+(And no language changes are needed.)
+
+Please note that I agree with Bob's conclusions, even if he somewhat
+misrepresents my position.
+ 
+****************************************************************
+
+From: Randy Brukardt
+Sent: Monday, February 16, 2009  10:53 PM
+
+...
+> (This one is not specifically about anonymous types.)  If you say 
+> "new" for one access type, convert to another type, and then 
+> Unchecked_Deallocate from the other type, it is implementation 
+> dependent whether this is erroneous.  In most compilers, it works just 
+> fine, and in fact people do it all the time.  To me, this is just an 
+> unacceptable non-portability.
+
+If the designated types are the same, and the pool is the same, I would
+expect it to work everywhere. (And I'm not sure why you think it wouldn't
+in that case.) OTOH, if the designated types are different, that means
+that the Size parameter to the Deallocate routine of a pool could be
+different than was allocated. And obviously, if the pool uses that
+parameter for something, havoc will occur. Indeed, the pre-Windows
+versions of Janus/Ada all would scramble memory in that case, because
+that parameter is the only way that they knew how much memory to put
+on the free list. Obviously, if too much was put there, bad things
+would happen. That's the definition of erroneous in my book.
+
+****************************************************************
+
+From: Bob Duff
+Sent: Tuesday, February 17, 2009  7:51 AM
+
+> > Anyway, I'm not trying to convince Randy that he's wrong -- Randy 
+> > can hide his access types if he likes.  I'm just trying to point out 
+> > that Randy's point of view is a minority one, so it would be wrong 
+> > to base the language design on that narrow view.
+> 
+> I would not argue that point, however.
+
+That's all I'm asking -- we can agree to disagree about access type
+philosophy, while agreeing to rein in the endless growth in complexity
+of them.  ;-)
+
+> The only other reason to avoid using the containers is because they 
+> are hard to use in some application. That we can fix, and indeed most 
+> of my emphasis has been on adding missing functionality to the 
+> containers and to the language to make the containers easier to use. 
+> (If it helps make other abstractions easier to use, that's even 
+> better.)
+
+That is a worthy goal.
+
+> If you know of some other reason for using access types rather than 
+> containers that are not covered by one of these two, I'd surely like 
+> to know what it is so it can be addressed in *this* cycle.
+
+No, please don't try to make containers applicable to _all_ current uses
+of access types.  Containers are about containment.
+
+Whenever you use an access type to "refer" to something ("reference
+semantics"), I don't see how a container can be applicable.  E.g., in a
+compiler, you might have a Usage_Name node, which contains a component
+pointing to a "symbol table entry".  The Usage_Name does not "contain" the
+symbol table entry, it points to (refers to) it.
+
+It doesn't have to be an access type -- it could be an index or something,
+but whatever it is, there's no "containment" relationship.
+
+Similar example: remember the "doctors/patients" thing?  A doctor
+conceptually contains a set of references to its patients, which might
+be implemented as a "set" container, but it's a set of _references_,
+not a set of patients.  (The patients don't disappear when the doctor does,
+for ex.)
+
+So I'm not asking for new container gizmos to deal with this.
+The "worthy goal" above is to make containers easier to use for cases
+involving "containment".
+
+Another example is recursive (treeish) data types:
+
+    type Binary_Op_Expression is new Expression with
+        record
+            Op: ...;
+            Left, Right : Expression'Class; -- Illegal!
+        end record;
+
+That's illegal, so I'd use an access type.  I saw the talk about
+Tree containers in some other thread, but I don't think anything like
+that would apply here.  I'm not asking for any language change, here.
+We already have plain old records to use as "containers" in this case,
+and it's not so horrible that we have to use access types to break up the
+recursive cases.
+
+****************************************************************
+
+From: Bob Duff
+Sent: Tuesday, February 17, 2009  8:01 AM
+
+> > (This one is not specifically about anonymous types.)  If you say 
+> > "new" for one access type, convert to another type, and then 
+> > Unchecked_Deallocate from the other type, it is implementation 
+> > dependent whether this is erroneous.  In most compilers, it works 
+> > just fine, and in fact people do it all the time.  To me, this is 
+> > just an unacceptable non-portability.
+> 
+> If the designated types are the same, and the pool is the same, I 
+> would expect it to work everywhere. (And I'm not sure why you think it 
+> wouldn't in that case.) OTOH, if the designated types are different, 
+> that means that the Size parameter to the Deallocate routine of a pool 
+> could be different than was allocated. And obviously, if the pool uses 
+> that parameter for something, havoc will occur. Indeed, the 
+> pre-Windows versions of Janus/Ada all would scramble memory in that 
+> case, because that parameter is the only way that they knew how much 
+> memory to put on the free list. Obviously, if too much was put there, 
+> bad things would happen. That's the definition of erroneous in my book.
+
+I'm talking about the case where there are no user-defined storage pools.
+And we have:
+
+    type Root is ...;
+    type Root_Ref is access all Root'Class;
+
+    type Child is new Root ...;
+    type Child_Ref is access all Child'Class;
+
+    type Grandchild is new Child...;
+    ...etc
+
+Now suppose "new" is done for Child_Ref, then the result is converted
+(or .all'Access-ed) to Root_Ref.  Much later, we Unchecked_Dealloc the
+Root_Ref value.
+
+This works just fine on many compilers, including GNAT.  And people do
+it all the time.  But the RM allows some compilers to make it erroneous.
+That's the "unacceptable non-portability" I'm talking about.
+
+I don't understand your concern about the size.  You need to calculate
+the size to pass to Deallocate based on the Tag, using a dispatching call
+(or equivalent).
+
+****************************************************************
+
+From: Bob Duff
+Sent: Tuesday, February 17, 2009  8:03 AM
+
+> Please note that I agree with Bob's conclusions, even if he somewhat 
+> misrepresents my position.
+
+I apologize for misrepresenting your position, and I'm still not sure I
+fully understand it.  But that's OK -- let's concentrate on the "conclusions",
+as you say.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Tuesday, February 17, 2009  3:11 PM
+
+...
+> > If you know of some other reason for using access types rather than 
+> > containers that are not covered by one of these two, I'd surely like 
+> > to know what it is so it can be addressed in *this* cycle.
+> 
+> No, please don't try to make containers applicable to _all_ current 
+> uses of access types.  Containers are about containment.
+> 
+> Whenever you use an access type to "refer" to something ("reference 
+> semantics"), I don't see how a container can be applicable.  E.g., in 
+> a compiler, you might have a Usage_Name node, which contains a 
+> component pointing to a "symbol table entry".  The Usage_Name does not 
+> "contain" the symbol table entry, it points to (refers to) it.
+
+Right, that's what a container cursor is for. When I'm talking about containers,
+I'm always talking about containers + cursors. Cursors take over the role
+of access types in most cases, having the advantage that they can be checked
+and detect most dangling cursors. The containers handle the storage management.
+No muss, no fuss. :-)
+
+> It doesn't have to be an access type -- it could be an index or 
+> something, but whatever it is, there's no "containment"
+> relationship.
+
+It's the cursor of the container, of course. I think you are thinking too
+narrowly. Keep in mind that you can do pretty much anything with a container
+cursor that you can do with an access type -- except conveniently dereference it
+(something I'd like to fix!!).
+
+> Similar example: remember the "doctors/patients" thing?  A doctor 
+> conceptually contains a set of references to its patients, which might 
+> be implemented as a "set" container, but it's a set of _references_, 
+> not a set of patients.  (The patients don't disappear when the doctor 
+> does, for ex.)
+> 
+> So I'm not asking for new container gizmos to deal with this.
+> The "worthy goal" above is to make containers easier to use for cases 
+> involving "containment".
+
+We don't need one; we already have it. The thing here is to remember that the
+data is somewhere (that's the container) and the relationships are the cursors
+to that container.
+
+> Another example is recursive (treeish) data types:
+> 
+>     type Binary_Op_Expression is new Expression with
+>         record
+>             Op: ...;
+>             Left, Right : Expression'Class; -- Illegal!
+>         end record;
+> 
+> That's illegal, so I'd use an access type.  I saw the talk about Tree 
+> containers in some other thread, but I don't think anything like that 
+> would apply here.
+
+This is *exactly* the sort of case that the tree containers are intended to
+handle. See my HTML example in that proposal (now AI05-0136-1). It's very
+similar to this example. It's not quite as convenient in the sense that naming
+the subcomponents takes more work (you'd probably want to write accessor functions
+called "Left" and "Right"), but again you don't have to do any memory management
+nor worry about dangling pointers. So I think you're usually ahead of the game.
+
+> I'm not asking for any
+> language change, here.  We already have plain old records to use as 
+> "containers" in this case, and it's not so horrible that we have to 
+> use access types to break up the recursive cases.
+
+But the point is that it isn't really necessary. Lists and Trees are (or should
+be) handled by the containers. I'm sure there must exist data structures that
+aren't handled by the containers (some sort of network graph comes to mind), but
+how often do you need one of those? I'd guess pretty much never. If we can make
+95% reasonably easy and reasonably safe (and reasonably efficient), I don't
+think it matters much how hard and messy the rest are. (And it is pretty good
+already, so long as you stay away from those anonymous abominations.)
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Tuesday, February 17, 2009  3:19 PM
+
+...
+> I'm talking about the case where there are no user-defined storage 
+> pools.
+> And we have:
+> 
+>     type Root is ...;
+>     type Root_Ref is access all Root'Class;
+> 
+>     type Child is new Root ...;
+>     type Child_Ref is access all Child'Class;
+> 
+>     type Grandchild is new Child...;
+>     ...etc
+> 
+> Now suppose "new" is done for Child_Ref, then the result is converted 
+> (or .all'Access-ed) to Root_Ref.  Much later, we Unchecked_Dealloc the 
+> Root_Ref value.
+> 
+> This works just fine on many compilers, including GNAT.  And people do 
+> it all the time.  But the RM allows some compilers to make it 
+> erroneous.  That's the "unacceptable non-portability" I'm talking 
+> about.
+> 
+> I don't understand your concern about the size.  You need to calculate 
+> the size to pass to Deallocate based on the Tag, using a dispatching 
+> call (or equivalent).
+
+I was speaking in general, not some rare special case! I say rare, because
+I've always avoided declaring things like Child_Ref; they just make a mess.
+Everything uses Root_Ref, right from the beginning. I just use conversions
+on the dereference "Child(Root.all)" to get to the components of Child
+(assuming I can't use dispatching). Moreover, this sort of thing illustrates
+exactly why you shouldn't put the access types visibly into the O-O abstractions
+in the first place. If you didn't do something stupid like that, you wouldn't
+have these stupid issues.
+
+Anyway, I was thinking more about constrained subtypes. In this case, a type like
+   type Root_Only_Ref is access all Root;
+If you take a reference to a child pointer and stuff it into this type, then
+deallocate, you'll definitely have trouble. Similarly with constrained and
+unconstrained subtypes. (I know some of these are illegal to convert, I don't
+have time to check out which examples are legal but of course there is always
+Unchecked_Conversion.)
+
+****************************************************************
+

Questions? Ask the ACAA Technical Agent