home *** CD-ROM | disk | FTP | other *** search
/ Solo Programadores 22 / SOLO_22.iso / docs / faq / prog / part2.dos / text0000.txt < prev   
Encoding:
Text File  |  1996-04-29  |  26.1 KB  |  643 lines

  1. Archive-name: computer-lang/Ada/programming/part2
  2. Comp-lang-ada-archive-name: programming/part2
  3. Posting-Frequency: monthly
  4. Last-modified: 28 February 1996
  5. Last-posted: 26 January 1996
  6.  
  7.                                Ada Programmer's
  8.                        Frequently Asked Questions (FAQ)
  9.  
  10.    IMPORTANT NOTE: No FAQ can substitute for real teaching and
  11.    documentation. There is an annotated list of Ada books in the
  12.    companion comp.lang.ada FAQ.
  13.  
  14. This is part 2 of a 4-part posting.
  15. Part 3 begins with question 6.
  16. Part 4 begins with question 9.
  17. Parts 3 and 4 should be the next postings in this thread.
  18. Part 1 should be the previous posting in this thread.
  19.  
  20.     Recent changes to this FAQ are listed in the first section after the table
  21.     of contents (in part 1). This document is under explicit copyright.
  22.  
  23.  
  24. 5: Object-Oriented Programming with Ada
  25.  
  26.  
  27. 5.1: Why does Ada have "tagged types" instead of classes?
  28.  
  29.    (Tucker Taft responds):
  30.  
  31.    Someone recently asked me to explain the difference between the
  32.    meaning of the term "class" in C++ and its meaning in Ada 9X. Here is
  33.    a synopsis of the answer:
  34.  
  35.    In C++, the term "class" refers to three different, but related
  36.    things:
  37.      * a language construct, that encapsulates the definitions of data
  38.        members, member functions, nested types, etc.;
  39.  
  40.      * a particular kind of type, defined by a class construct (or by
  41.        "struct" which is a special case of "class");
  42.  
  43.      * a set of types consisting of a type and all of its derivatives,
  44.        direct and indirect.
  45.  
  46.  
  47.    In Ada 9X, the term "class" refers only to the third of the above
  48.    definitions. Ada 9X (and Ada 83) has three different terms for the
  49.    concepts corresponding to the above three things:
  50.      * a "package" encapsulates the definitions of types, objects,
  51.        operations, exceptions, etc which are logically related. (The
  52.        operations of a type defined immediately within the package where
  53.        the type is declared are called, in 9X, the "primitive operations"
  54.        of the type, and in some sense, define the "primitive" semantics
  55.        of the type, especially if it is a private type.)
  56.  
  57.      * a "type" is characterized by a set of values and a set of
  58.        primitive operations (there are a million definitions of "type,"
  59.        unfortunately, but you know what I mean...);
  60.  
  61.      * a "class" is a set of types with similar values and operations; in
  62.        particular, a type and and all of its derivatives, direct and
  63.        indirect, represents a (derivation) class. Also, the set of
  64.        integer types form the integer "class," and so on for the other
  65.        language-defined classes of types in the language.
  66.  
  67.  
  68.    Some OOP languages take an intermediary position. In CLOS, a "class"
  69.    is not an encapsulating construct (CLOS has "packages"). However, a
  70.    "class" is both a type and a set of types, depending on context.
  71.    (Methods "float" freely.)
  72.  
  73.    The distinction Ada 9X makes between types and classes (= set of
  74.    types) carries over into the semantic model, and allows some
  75.    interesting capabilities not present in C++. In particular, in Ada 9X
  76.    one can declare a "class-wide" object initialized by copy from a
  77.    "class-wide" formal parameter, with the new object carrying over the
  78.    underlying type of the actual parameter. For example:
  79.  
  80.      procedure Print_In_Bold (X : T'Class) is
  81.        -- Copy X, make it bold face, and then print it.
  82.        Copy_Of_X : T'Class := X;
  83.      begin
  84.         Make_Bold (Copy_Of_X);
  85.         Print (Copy_Of_X);
  86.      end P;
  87.  
  88.  
  89.    In C++, when you declare an object, you must specify the "exact" class
  90.    of the object -- it cannot be determined by the underlying class of
  91.    the initializing value. Implementing the above procedure in a general
  92.    way in C++ would be slightly more tedious.
  93.  
  94.    Similarly, in Ada 9X one can define an access type that designates
  95.    only one specific type, or alternatively, one can define one that can
  96.    designate objects of any type in a class (a "class-wide" access type).
  97.    For example:
  98.  
  99.      type Fancy_Window_Ptr is access Fancy_Window;
  100.        -- Only points at Fancy Windows -- no derivatives allowed
  101.      type Any_Window_Ptr is access Window'Class;
  102.        -- Points at Windows, and any derivatives thereof.
  103.  
  104.  
  105.    In C++, all pointers/references are "class-wide" in this sense; you
  106.    can't restrict them to point at only one "specific" type.
  107.  
  108.    In other words, C++ makes the distinction between "specific" and
  109.    "class-wide" based on pointer/reference versus object/value, whereas
  110.    in Ada 9X, this distinction is explicit, and corresponds to the
  111.    distinction between "type" (one specific type) and "class" (set of
  112.    types).
  113.  
  114.    The Ada 9X approach we believe (hope ;-) gives somewhat better control
  115.    over static versus dynamic binding, and is less error prone since it
  116.    is type-based, rather than being based on reference vs. value.
  117.  
  118.    In any case, in Ada 9X, C++, and CLOS it makes sense to talk about
  119.    "class libraries," since a given library will generally consist of a
  120.    set of interrelated types. In Ada 9X and CLOS, one could alternatively
  121.    talk about a set of "reusable packages" and mean essentially the same
  122.    thing.
  123.  
  124.  
  125. 5.2: Variant records seem like a dead feature now. When should I use them
  126. instead of tagged types?
  127.  
  128.    This is an instance of a much more general question: "When should I
  129.    use what kind of type?" The simple answer is: "When it makes sense to
  130.    do so." The real key to chosing a type in Ada is to look at the
  131.    application, and pick the type that most closely models the problem.
  132.  
  133.    For instance, if you are modelling data transmission where the message
  134.    packets may contain variable forms of data, a variant record --not a
  135.    hierarchy of tagged types-- is an appropriate model, since there may
  136.    be no relationship between the data items other than their being
  137.    transmitted over one channel. If you choose to model the base type of
  138.    the messages with a tagged type, that may present more problems than
  139.    it solves when communicating across distinct architectures.
  140.  
  141.    [More to be said about variant programming vs. incremental
  142.    programming.]
  143.  
  144.  
  145. 5.3: What is meant by "interface inheritance" and how does Ada support it?
  146.  
  147.    This answer intentionally left blank.
  148.  
  149.  
  150. 5.4: How do you do multiple inheritance in Ada 9X?
  151.  
  152.    There is a lengthy paper in file
  153.    ftp://sw-eng.falls-church.va.us/public/AdaIC/flyers/9xm-inh.txt
  154.  
  155.    That document describes several mechanisms for achieving MI in Ada. It
  156.    is not unusual, however, to find complaints about the syntax and the
  157.    perceived burden it places on the developer. This is what Tucker Taft
  158.    had to say when responging to such a criticism on comp.lang.ada:
  159.  
  160.    Coming up with a syntax for multiple inheritance was not the
  161.    challenge. The challenge was coming up with a set of straightforward
  162.    yet flexible rules for resolving the well known problems associated
  163.    with multiple inheritance, namely:
  164.      * If the same type appears as an ancestor more than once, should all
  165.        or some of its data components be duplicated, or shared? If any
  166.        are duplicated, how are they referenced unambiguously?
  167.  
  168.      * If the same-named (including same parameter/result profile)
  169.        operation is inherited along two paths, how is the ambiguity
  170.        resolved? Can you override each with different code? How do you
  171.        refer to them later?
  172.  
  173.      * Etc.
  174.  
  175.  
  176.    For answers, you can look at the various languages that define a
  177.    built-in approach to multiple inheritance. Unfortunately, you will
  178.    generally get a different answer for each language -- hardly a
  179.    situation that suggests we will be able to craft an international
  180.    consensus. Eiffel uses renaming and other techniques, which seem quite
  181.    flexible, but at least in some examples, can be quite confusing (where
  182.    you override "B" to change what "A" does in some distant ancestor).
  183.    C++ has both non-virtual and virtual base clases, with a number of
  184.    rules associated with each, and various limitations relating to
  185.    downcasting and virtual base classes. CLOS uses simple name matching
  186.    to control "slot" merging. Some languages require that all but one of
  187.    the parent types be abstract, data-less types, so only interfaces are
  188.    being inherited; however if the interfaces happen to collide, you
  189.    still can end up with undesirable and potentially unresolvable
  190.    collisions (where you really want different code for same-named
  191.    interfaces inherited from different ancestors).
  192.  
  193.    One argument is that collisions are rare to begin with, so it doesn't
  194.    make much different how they are resolved. That is probably true, but
  195.    the argument doesn't work too well during an open language design
  196.    process -- people get upset at the most unbelievably trivial and
  197.    rarely used features if not "correctly" designed (speaking from
  198.    experience here ;-).
  199.  
  200.    Furthermore, given that many of the predominant uses of MI (separation
  201.    of interface inheritance from implementation inheritance, gaining
  202.    convenient access to another class's features, has-a relationships
  203.    being coded using MI for convenience, etc.) are already handled very
  204.    well in Ada 9X, it is hard to justify getting into the MI language
  205.    design fray at all. The basic inheritance model in Ada 9X is simple
  206.    and elegant. Why clutter it up with a lot of relatively ad-hoc rules
  207.    to handle one particular approach to MI? For the rare cases where MI
  208.    is really critical, the last thing the programmer wants in the
  209.    language is the "wrong" MI approach built in.
  210.  
  211.    So the basic answer is that at this point in the evolution of OO
  212.    language design, it seemed wiser to provide MI building blocks, rather
  213.    than to foist the wrong approach on the programmer, and be regretting
  214.    it and working around it for years to come.
  215.  
  216.    Perhaps [Douglas Arndt] said it best...
  217.  
  218.      Final note: inheritance is overrated, especially MI. ...
  219.  
  220.  
  221.    If the only or primary type composition mechanism in the language is
  222.    based on inheritance, then by all means, load it up. But Ada 9X
  223.    provides several efficient and flexible type composition mechanisms,
  224.    and there is no need to overburden inheritance with unnecessary and
  225.    complicated baggage.
  226.  
  227.  
  228. 5.5: Why are Controlled types so, well, strange?
  229.  
  230.    (Tucker Taft responds):
  231.  
  232.    We considered many approaches to user-defined finalization and
  233.    user-defined assignment. Ada presents challenges that make it harder
  234.    to define assignment than in other languages, because assignment is
  235.    used implicitly in several operations (by-copy parameter passing,
  236.    function return, aggregates, object initialization, initialized
  237.    allocators, etc.), and because Ada has types whose set of components
  238.    can be changed as a result of an assignment.
  239.  
  240.    For example:
  241.  
  242.      type T (D : Boolean := False) is record
  243.        case D is
  244.          when False => null;
  245.          when True => H : In_Hands;
  246.        end case;
  247.      end record;
  248.  
  249.      X,Z : T;
  250.      Y : T := (True, H => ...);
  251.  
  252.      ...
  253.  
  254.      X := Y;   -- "X.H" component coming into existence
  255.      Y := Z;   -- "Y.H" component going out of existence
  256.  
  257.  
  258.    With a type like the one above, there are components that can come and
  259.    go as a result of assignment. The most obvious definition of
  260.    assignment would be:
  261.  
  262.      procedure ":=" (Left : in out In_Hands; Right : in In_Hands);
  263.  
  264.  
  265.    Unfortunately, this wouldn't work for the "H" component, because there
  266.    is no preexisting "In_Hands" component to be assigned into in the
  267.    first case, and in the second case, there is no "In_Hands" component
  268.    to assign "from."
  269.  
  270.    Therefore, we decided to decompose the operation of assignment into
  271.    separable pieces: finalization of the left hand side; simple copying
  272.    of the data from the right hand side to the left hand side; and then
  273.    adjustment of the new left hand side. Other decompositions are
  274.    probably possible, but they generally suffer from not being easily
  275.    composable, or not handling situations like the variant record above.
  276.  
  277.    Imagine a function named ":=" that returns a copy of its in parameter.
  278.    To do anything interesting it will have to copy the in parameter into
  279.    a local variable, and then "fiddle" with that local variable
  280.    (essentially what "Adjust" does), and then return that local variable
  281.    (which will make yet another copy). The returned result will have to
  282.    be put back into the desired place (which might make yet another
  283.    copy). For a large object, this might involve several extra copies.
  284.  
  285.    By having the user write just that part of the operation that
  286.    "fiddles" with the result after making a copy, we allow the
  287.    implementation to eliminate redundant copying. Furthermore, some
  288.    user-defined representations might be position dependent. That is, the
  289.    final "fiddling" has to take place on the object in its final
  290.    location. For example, one might want the object to point to itself.
  291.    If the implementation copies an object after the user code has
  292.    adjusted it, such self-references will no longer point to the right
  293.    place.
  294.  
  295.    So, as usual, once one gets into working out the details and all the
  296.    interactions, the "obvious" proposal (such as a procedure ":=") no
  297.    longer looks like the best answer, and the best answer one can find
  298.    potentially looks "clumsy" (at least before you try to work out the
  299.    details of the alternatives).
  300.  
  301.  
  302. 5.6: What do "covariance" and "contravariance" mean, and does Ada support
  303. either or both?
  304.  
  305.    (From Robert Martin) [This is C++ stuff, it should be completely
  306.    re-written for Ada. --MK]
  307.  
  308.  
  309.  R> covariance:  "changes with"
  310.  R> contravariance: "changes against"
  311.  
  312.  R> class A
  313.  R> {
  314.  R>    public:
  315.  R>      A* f(A*);   // method of class A, takes A argument and returns A
  316.  R>      A* g(A*);   // same.
  317.  R> };
  318.  
  319.  R> class B : public A // class B is a subclass of class A
  320.  R> {
  321.  R>   public:
  322.  R>     B* f(B*);  // method of class B overrides f and is covariant.
  323.  R>     A* g(A*);  // method of class B overrides g and is contravariant.
  324.  R> };
  325.  
  326.  R> The function f is covariant because the type of its return value and
  327.  R> argument changes with the class it belongs to.  The function g is
  328.  R> contravariant because the types of its return value and arguments does not
  329.  R> change with the class it belongs to.
  330.  
  331.  
  332.    Actually, I would call g() invariant. If you look in Sather, (one of
  333.    the principle languages with contravariance), you will see that the
  334.    method in the descendant class actually can have arguments that are
  335.    superclasses of the arguments of its parent. So for example:
  336.  
  337. class A : public ROOT
  338. {
  339.    public:
  340.      A* f(A*);   // method of class A, takes A argument and returns A
  341.      A* g(A*);   // same.
  342. };
  343.  
  344. class B : public A // class B is a subclass of class A
  345. {
  346.   public:
  347.     B* f(B*);  // method of class B overrides f and is covariant.
  348.     ROOT* g(ROOT*);  // method of class B overrides g and is contravariant.
  349. };
  350.  
  351.  
  352.    To my knowledge the uses for contravariance are rare or nonexistent.
  353.    (Anyone?). It just makes the rules easy for the compiler to type
  354.    check. On the other hand, co-variance is extremely useful. Suppose you
  355.    want to test for equality, or create a new object of the same type as
  356.    the one in hand:
  357.  
  358. class A
  359. {
  360.    public:
  361.       BOOLEAN equal(A*);
  362.       A* create();
  363. }
  364.  
  365. class B: public A
  366. {
  367.    public:
  368.       BOOLEAN equal(B*);
  369.       B* create();
  370. }
  371.  
  372.  
  373.    Here covariance is exactly what you want. Eiffel gives this to you,
  374.    but the cost is giving up 100% compile time type safety. This seem
  375.    necessary in cases like these.
  376.  
  377.    In fact, Eiffel gives you automatic ways to make a method covariant,
  378.    called "anchored types". So you could declare, (in C++/eiffese):
  379.  
  380. class A
  381. {
  382.    public:
  383.       BOOLEAN equal(like Current *);
  384.       like Current * create();
  385. }
  386.  
  387.  
  388.    Which says equal takes an argument the same type as the current
  389.    object, and create returns an object of the same type as current. Now,
  390.    there is not even any need to redeclare these in class B. Those
  391.    transformations happen for free!
  392.  
  393.  
  394. 5.7: What is meant by upcasting/expanding and downcasting/narrowing?
  395.  
  396.    (Tucker Taft replies):
  397.  
  398.    Here is the symmetric case to illustrate upcasting and downcasting.
  399.  
  400.      type A is tagged ...;   -- one parent type
  401.  
  402.      type B is tagged ...;   -- another parent type
  403.  
  404.      ...
  405.  
  406.      type C;   -- the new type, to be a mixture of A and B
  407.  
  408.      type AC (Obj : access C'Class) is
  409.        new A
  410.        with ...;
  411.        -- an extension of A to be mixed into C
  412.  
  413.      type BC (Obj : access C'Class) is
  414.        new B
  415.        with ...;
  416.        -- an extension of B to be mixed into C
  417.  
  418.      type C is
  419.        tagged limited record
  420.          A : AC (C'Access);
  421.          B : BC (C'Access);
  422.          ... -- other stuff if desired
  423.        end record;
  424.  
  425.  
  426.    We can now pass an object of type C to anything that takes an A or B
  427.    as follows (this presumes that Foobar and QBert are primitives of A
  428.    and B, respectively, so they are inherited; if not, then an explicit
  429.    conversion (upcast) to A and B could be used to call the original
  430.    Foobar and QBert).
  431.  
  432.      XC : C;
  433.    ...
  434.      Foobar (XC.A);
  435.      QBert (XC.B);
  436.  
  437.  
  438.    If we want to override what Foobar does, then we override Foobar on
  439.    AC. If we want to override what QBert does, then we override QBert on
  440.    BC.
  441.  
  442.    Note that there are no naming conflicts, since AC and BC are distinct
  443.    types, so even if A and B have same-named components or operations, we
  444.    can talk about them and/or override them individually using AC and BC.
  445.  
  446.  
  447.    Upcasting (from C to A or C to B) is trivial -- A(XC.A) upcasts to A;
  448.    B(XC.B) upcasts to B.
  449.  
  450.    Downcasting (narrowing) is also straightforward and safe. Presuming XA
  451.    of type A'Class, and XB of type B'Class:
  452.  
  453.      AC(XA).Obj.all downcasts to C'Class (and verifies XA in AC'Class)
  454.      BC(XB).Obj.all downcasts to C'Class (and verifies XB in BC'Class)
  455.  
  456.  
  457.    You can check before the downcast to avoid a Constraint_Error:
  458.  
  459.      if XA not in AC'Class then -- appropriate complaint
  460.  
  461.      if XB not in BC'Class then -- ditto
  462.  
  463.  
  464.    The approach is slightly simpler (though less symmetric) if we choose
  465.    to make A the "primary" parent and B a "secondary" parent:
  466.  
  467.      type A is ...
  468.      type B is ...
  469.  
  470.      type C;
  471.  
  472.      type BC (Obj : access C'Class) is
  473.        new B
  474.        with ...
  475.  
  476.      type C is
  477.        new A
  478.        with record
  479.          B : BC (C'Access);
  480.          ... -- other stuff if desired
  481.        end record;
  482.  
  483.  
  484.    Now C is a "normal" extension of A, and upcasting from C to A and
  485.    (checked) downcasting from C'Class to A (or A'Class) is done with
  486.    simple type conversions. The relationship between C and B is as above
  487.    in the symmetric approach.
  488.  
  489.    Not surprisingly, using building blocks is more work than using a
  490.    "builtin" approach for simple cases that happen to match the builtin
  491.    approach, but having building blocks does ultimately mean more
  492.    flexibility for the programmer -- there are many other structures that
  493.    are possible in addition to the two illustrated above, using the
  494.    access discriminant building block.
  495.  
  496.    For example, for mixins, each mixin "flavor" would have an access
  497.    discriminant already:
  498.  
  499.      type Window is ...  -- The basic "vanilla" window
  500.  
  501.      -- Various mixins
  502.      type Win_Mixin_1 (W : access Window'Class) is ...
  503.  
  504.      type Win_Mixin_2 (W : access Window'Class) is ...
  505.  
  506.      type Win_Mixin_3 (W : access Window'Class) is ...
  507.  
  508.  
  509.    Given the above vanilla window, plus any number of window mixins, one
  510.    can construct a desired window by including as many mixins as wanted:
  511.  
  512.      type My_Window is
  513.        new Window
  514.        with record
  515.          M1 : Win_Mixin_1 (My_Window'access);
  516.          M3 : Win_Mixin_3 (My_Window'access);
  517.          M11 : Win_Mixin_1(My_Window'access);
  518.          ... -- plus additional stuff, as desired.
  519.        end record;
  520.  
  521.  
  522.    As illustrated above, you can incorporate the same "mixin" multiple
  523.    times, with no naming conflicts. Every mixin can get access to the
  524.    enclosing object. Operations of individual mixins can be overridden by
  525.    creating an extension of the mixin first, overriding the operation in
  526.    that, and then incorporating that tweaked mixin into the ultimate
  527.    window.
  528.  
  529.    I hope the above helps better illustrate the use and flexibility of
  530.    the Ada 9X type composition building blocks.
  531.  
  532.  
  533. 5.8: How does Ada do "narrowing"?
  534.  
  535.    Dave Griffith said
  536.  
  537.      . . . Nonetheless, The Ada9x committee chose a structure-based
  538.      subtyping, with all of the problems that that is known to cause. As
  539.      the problems of structure based subtyping usually manifest only in
  540.      large projects maintained by large groups, this is _precisely_ the
  541.      subtype paradigm that Ada9x should have avoided. Ada9x's model is,
  542.      as Tucker Taft pointed out, quite easy to use for simple OO
  543.      programming. There is, however, no good reason to _do_ simple OO
  544.      programming. OO programmings gains click in somewhere around 10,000
  545.      LOC, with greatest gains at over 100,000. At these sizes, "just
  546.      declare it tagged" will result in unmaintainable messes. OO
  547.      programming in the large rapidly gets difficult with structure based
  548.      subtyping. Allowing by-value semantics for objects compounds these
  549.      problems. All of this is known. All of this was, seemingly, ignored
  550.      by Ada9x.
  551.  
  552.  
  553.    (Tucker Taft answers)
  554.  
  555.    As explained in a previous note, Ada 9X supports the ability to hide
  556.    the implementation heritage of a type, and only expose the desired
  557.    interface heritage. So we are not stuck with strictly "structure-based
  558.    subtyping." Secondly, by-reference semantics have many "well known"
  559.    problems as well, and the designers of Modula-3 chose to, seemingly,
  560.    ignore those ;-) ;-). Of course, in reality, neither set of language
  561.    designers ignored either of these issues. Language design involves
  562.    tradeoffs. You can complain we made the wrong tradeoff, but to
  563.    continue to harp on the claim that we "ignored" things is silly. We
  564.    studied every OOP language under the sun on which we could find any
  565.    written or electronic material. We chose value-based semantics for
  566.    what we believe are good reasons, based on reasonable tradeoffs.
  567.  
  568.    First of all, in the absence of an integrated garbage collector,
  569.    by-reference semantics doesn't make much sense. Based on various
  570.    tradeoffs, we decided against requiring an integrated garbage
  571.    collector for Ada 9X.
  572.  
  573.    Secondly, many of the "known" problems with by-value semantics we
  574.    avoided, by eliminating essentially all cases of "implicit
  575.    truncation." One of the problems with the C++ version of "value
  576.    semantics" is that on assignment and parameter passing, implicit
  577.    truncation can take place mysteriously, meaning that a value that
  578.    started its life representing one kind of thing gets truncated
  579.    unintentionally so that it looks like a value of some ancestor type.
  580.    This is largely because the name of a C++ class means differnt things
  581.    depending on the context. When you declare an object, the name of the
  582.    class determines the "exact class" of the object. The same thing
  583.    applies to a by-value parameter. However, for references and pointers,
  584.    the name of a class stands for that class and all of its derivatives.
  585.    But since, in C++, a value of a subclass is always acceptable where a
  586.    value of a given class is expected, you can get implicit truncation as
  587.    part of assignment and by-value parameter passing. In Ada 9X, we avoid
  588.    the implicit truncation because we support assignment for "class-wide"
  589.    types, which never implicitly truncates, and one must do an explicit
  590.    conversion to do an assignment that truncates. Parameter passing never
  591.    implicitly truncates, even if an implicit conversion is performed as
  592.    part of calling an inherited subprogram.
  593.  
  594.  
  595. 5.9: What is the difference between a class-wide access type and a "general"
  596. class-wide access type?
  597.  
  598.      What is exactly the difference between
  599.  
  600. type A is access Object'Class;
  601.  
  602.      and
  603.  
  604. type B is access all Object'Class;
  605.  
  606.      In the RM and Rationale only definitions like B are used. What's the
  607.      use for A-like definitions ?
  608.  
  609.  
  610.    (Tucker Taft answers)
  611.  
  612.    The only difference is that A is more restrictive, and so presumably
  613.    might catch bugs that B would not. A is a "pool-specific" access type,
  614.    and as such, you cannot convert values of other access types to it,
  615.    nor can you use 'Access to create values of type A. Values of type A
  616.    may only point into its "own" pool; that is only to objects created by
  617.    allocators of type A. This means that unchecked-deallocation is
  618.    somewhat safer when used with a pool-specific type like A.
  619.  
  620.    B is a "general" access type, and you can allocate in one storage
  621.    pool, and then convert the access value to type B and store it into a
  622.    variable of type B. Similarly, values of type B may point at objects
  623.    declared "aliased."
  624.  
  625.    When using class-wide pointer types, type conversion is sometimes used
  626.    for "narrowing." This would not in general be possible if you had left
  627.    out the "all" in the declaration, as in the declaration of A. So, as a
  628.    general rule, access-to-classwide types usually need to be general
  629.    access types. However, there is no real harm in starting out with a
  630.    pool-specific type, and then if you find you need to do a conversion
  631.    or use 'Access, the compiler should notify you that you need to add
  632.    the "all" in the declaration of the type. This way you get the added
  633.    safety of using a pool-specific access type, until you decide
  634.    explicitly that you need the flexibility of general access types.
  635.  
  636.    In some implementations, pool-specific access types might have a
  637.    shorter representation, since they only need to be able to point at
  638.    objects in a single storage pool. As we move toward 64-bit address
  639.    spaces, this might be a significant issue. I could imagine that
  640.    pool-specific access types might remain 32-bits in some
  641.    implementations, while general access types would necessarily be
  642.    64-bits.
  643.