CVS difference for ais/ai-00251.txt

Differences between 1.14 and version 1.15
Log of other versions for file ais/ai-00251.txt

--- ais/ai-00251.txt	2003/07/26 03:26:00	1.14
+++ ais/ai-00251.txt	2003/09/19 01:42:26	1.15
@@ -1,4 +1,4 @@
-!standard 03.04    (02)                            03-05-23  AI95-00251/07
+!standard 03.04    (02)                            03-09-02  AI95-00251/08
 !standard 03.09.01 (02)
 !class amendment 00-12-04
 !status work item 00-12-04
@@ -12,10 +12,9 @@
 This proposal adds "interface" types to the standard as a kind of
 componentless abstract tagged type. A tagged type may be
 derived from one or more such interfaces; this provides a limited form
-of multiple inheritance. The classwide type associated with
-the interface "covers" all types that implement it. Dispatching calls through
-the primitives of the interface type dispatch to code bodies associated with
-specific tagged types that are derived from the interface.
+of multiple inheritance. Dispatching calls through the primitives of the
+interface type dispatch to code bodies associated with specific tagged types
+that are derived from the interface.
 
 !problem
 
@@ -52,18 +51,8 @@
 their primitive subprograms.
 
 The primitive subprograms of an interface type must either be abstract
-or "null". A "null" procedure is a procedure declaration of the (newly
-introduced) form
+or "null" (See AI-348 for the definition of null procedures).
 
-     procedure P (...) is null;
-
-whose dynamic semantics are similar to a procedure with the body
-
-     procedure P (...) is
-     begin
-         null;
-     end;
-
 The class-wide type corresponding to an interface type covers all of the
 types derived from that interface type. This allows conversion between
 the classwide type and any type which is derived from the interface type.
@@ -100,13 +89,11 @@
 discussed below), or require recompilation of inherited primitives even when
 not overridden. Inheritance then becomes more like macro expansion.
 
-The rules are structured to ensure that an existing abstract tagged type can be
-changed to being an abstract interface type with minimal disruption to the
-existing code. The intent is that essentially anywhere an abstract tagged
-private (or null record) type is permitted, an interface is similarly
-permitted. Of course, there are additional places where only interfaces are
-allowed, but hopefully none where abstract private/null-record types are
-permitted, but interfaces are not.
+The rules are structured to ensure that an existing componentless
+abstract tagged type can be changed to being an interface type with
+minimal disruption to the existing code. Because an interface type is
+an abstract tagged type, it can be used anywhere an abstract tagged private
+(or null record) type is permitted.
 
 We disallow "private" inheriting from interfaces, because without
 allocating a complete separate set of dispatching operation "slots"
@@ -120,224 +107,96 @@
        ...
     private
         type T1 is new Foo and I with ...
-        procedure prim_of_I(X : T1);
+        procedure Prim_Of_I(X : T1);
     end P;
 
     ...
     type T2 is new P1.T1 and I with ...
-    procedure prim_of_I(X : T2);
-        -- if operations of I are overridden for T2 (like prim_of_I), they
+    procedure Prim_Of_I(X : T2);
+        -- if operations of I are overridden for T2 (like Prim_Of_I), they
         -- will override operations associated with T1's "private"
         -- inheritance of I, violating the "privateness" of the
         -- inheritance.
 
-In the above case, the partial view of T1 would need to be:
+In the above case, the partial view of T1 could be:
 
     type T1 is new I with private;
 
-This would make it visible that I is inherited, and thereby making
+This would make it visible that I is inherited, and thereby marking
 the primitives of "I" as fair game for overriding outside P.
 
-        "Null" Primitives Rationale
-
-The ability to declare a primitive of an interface as "is null"
-enables existing abstract types that have null (non-abstract) default
-implementations of some of their primitives to be transitioned to being
-abstract interface types. An example of such a type is
-Ada.Finalization.Controlled. [Note that there are other
-considerations which might argue for leaving Controlled as a "normal" tagged
-type, but the capability of switching other existing abstract tagged types to
-be interfaces remains potential quite useful, in our view.]
-
-The ability to have non-dispatching calls on the primitive of a generic
-formal interface type to be made inside the generic can be necessary to
-enable a pass-the-buck-to-the-parent paradigm when overriding the
-operation. This is the paradigm used for finalization, for example,
-and is quite common in type hierarchies in general.
-
-For example:
-     type T is abstract interface;
-     procedure Prim1(X : T) is null;
-     procedure Prim2(X : T) is abstract;
-
-     generic
-         type NT is abstract new T with private;
-          -- NT guaranteed to have non-abstract implementation of Prim1
-     package P is
-         type NN is new NT with private;
-         procedure Prim1(X : NN);
-             -- may "pass-the-buck" to Prim1 of NT as part
-             -- of implementation of Prim1 of NN.
-         procedure Prim2(X : NN);
-             -- Prim2 must be overridden;
-             -- cannot call Prim2 of NT since might be abstract
-     end P;
-
-
-Being able to declare "is null" in the spec of a primitive procedure has other
-advantages. For example, for code in a generic which always "passes the buck"
-to the corresponding parent primitive (as is done for Finalize, for example),
-the compiler can eliminate such a call when the parent's operation is known
-null at instantiation time. There are also obvious documentation advantages
-for someone extending a type to know that the default implementation of an
-operation is null. These advantages exist independently of this proposal for
-interfaces.
-
-Like an instantiation, a null procedure is not allowed as a completion.
-Allowing this would double the amount of RM text needed for no real gain.
-
-A null procedure may have OUT-mode parameters, the same as a
-conventional "begin null; end;" procedure. There doesn't seem to be any
-reason to require an incompatiblity here.
-
-Having null procedures, it may make sense to change the spec of
-Ada.Finalization to define Initialize, Finalize, and Adjust as null procedures.
-7.6(9) does this in words currently, and it makes sense to use this feature
-to make that definition more explicit.
-
-
         Possible Implementation Model
+
+As an implementation model, one can think of a type which
+inherits operations from an interface type as defining a
+mapping from the primitive operations of the interface type (perhaps
+represented as dispatch table slot numbers) to those of the inheriting type.
+A dispatching call to an operation of an interface type is then accomplished
+by mapping the called operation to the corresponding
+operation of the controlling operand's type. Alternatively, one
+might construct a separate dispatch table representing this
+alternative "view" of the "real" dispatch table, but that would
+require more work when deriving from a type which implements
+an interface. The slot-to-slot mapping remains valid and can be
+reused for the derived type, whereas a new alternative "view"
+of the dispatch table of the derived type would need to be
+constructed. A value of type Some_InterFace_Type'Class can then
+be represented at runtime as a record address paired (perhaps only
+conceptually - see next paragraph) with a reference to this dispatch
+table permutation map.
 
-A possible implementation model for an interface "view" of an object is to use
-a pair of pointers, one to an interface-specific dispatch table, and the other
-to the tagged object of the implementing type. The interface-specific dispatch
+Consider the example of a call to Some_Interface_Type'Class'Input
+occuring as the controlling operand of a dispatching call. The
+implementation must be able to determine where to dispatch to in this case.
+In terms of the "slot-to-slot mapping" implementation model,
+this means that an implementation needs to provide a mapping at runtime
+which takes the tag of a specific tagged type and of an interface type
+(which is implemented by the specific type) and returns a
+reference to the associated dispatch table permutation map (aka the
+"slot-to-slot" map). Given this mapping, a "thin pointer" representation
+becomes feasible. In other words, a value of type Some_InterFace_Type'Class
+could be represented as an unaugmented record record address.
+
+Alternatively, a "fat pointer" implementation model is possible.
+An interface "view" of an object is represented as a pair of pointers, one to
+an interface-specific dispatch table (or permutation map), and the other to
+the tagged object of the implementing type. The interface-specific dispatch
 table would have a layout determined by the order in which the primitives of
 the interface were declared, while its content would be determined by the
 particular type implementing the interface.
 
-If a given type (including potentially an interface) implements one or more
-interfaces, appropriate dispatching tables for these other interfaces should be
-efficiently accessible via the given type's dispatch table (as well as the
-dispatch table of any descendant of the type). A suggested model is to have in
-the dispatch table a pointer to an array of interfaces implemented by the type
-(where an interface is represented by a pointer to its dispatch table). This
-interface array would be organized so that a given interface is at a
-compile-time known offset in the array, analogous to how an individual dispatch
-table of primitive subprograms is laid out.
-
-This interface array allows an efficient view conversion from the given type to
-one of its interfaces, by fetching the desired interface (dispatch table) from
-the compile-time known slot in the interface array. Descendants of a type would
-add further interfaces to the end of this array of interfaces, so the offsets
-within the array for earlier interfaces remain the same.  This model also
-applies if we define a "descendant" of an interface to be any interface or
-tagged type that names the interface immediately after the word "NEW" in its
-declaration (as opposed to naming it after an "AND").
-
-Converting from an interface view to a non-interface view that implements it
-can be performed using an approach commonly used in Ada 95 to convert to a
-descendant tagged type, by checking a table of ancestors to see if the target
-type appears at the appropriate level in the table. On the other hand,
-converting from one interface view to another one that implements it will
-generally require more overhead, both for the view conversion and the
-associated run-time check. Essentially the same two approaches would be
-involved in a membership test.
-
-One mechanism to support interface-to-interface view conversion is to do a
-run-time search through a directory (perhaps a hash table) of all implemented
-interfaces, indexed by a unique identifier of the interface (such as the value
-returned by 'Tag), and containing a reference to the corresponding dispatch
-table for the interface. Note that this directory is *not* the same thing as
-the "interface array" mentioned above, because the unique identifier of the
-associated interface is not included in that array. Furthermore, multiple
-interfaces can share the same slot in an interface array, but each needs their
-own entry in this directory. If the target interface is found in this
-directory, then the conversion would pick up the corresponding
-interface-specific dispatch table. If the target interface is not found, then
-the conversion would raise Constraint_Error.
-
-If it is desired to share these directories between types that implement the
-same set of interfaces and have the same interface array layout, this directory
-could contain the slot number of the interface within the interface array,
-rather than a direct pointer to the dispatch table for the interface.
-
-
-        "Thin Pointer" Implementation Model
-
-It is still possible to implement references to interfaces using single-word
-pointers, but there is additional overhead when a call is to be performed.
-Essentially the same data structures suggested above can be used, but the
-directory of interfaces is searched to find the dispatch table before
-dispatching. The result of this search can be saved and reused, so that if
-there are multiple calls using the same interface reference, the directory
-search need only be performed once. In fact, one could use "fat" pointers for
-some or all parameter passing, and "thin" pointers for access-to-interfaces,
-and thereby only incur the expense when dereferencing an access value rather
-than upon individual calls. This combination of fat/thin is similar to the
-approach used in many compilers for access-to-unconstrained-arrays, where the
-access values are thin but two words are used for parameter passing.
-
-        Shared Generics
-
-For implementations that share code between generic instantiations, we need to
-ensure that the addition of interfaces to the languages does not impose
-distributed overhead on programs that make no use of interfaces. If there are
-cases where an actual type can be an interface when the formal is not, clearly
-a shared generic implementation will choose to represent the formal as a
-"normal" tagged type. In particular an access-to-formal would be "thin."  What
-are the implications of this? If there is a formal access type with the formal
-as the designated type, if the actual is not also "thin" there would be
-significant overhead. This implies that either we disallow an interface
-"masquerading" as a "normal" tagged type, or use thin pointers for all
-access-to-interface types.
-
-An alternative is to use fat pointers for "normal" tagged types that could
-match the same formal as that matched by an interface. For example, in the
-rules proposed above, an interface does not match an abstract private type, but
-does match an abstract formal extension that has only interfaces specified
-after "NEW." This would mean that any normal tagged type that implements one
-or more interfaces would also have to use fat pointers, even though both words
-would point to the same dispatch table.
+Intermediate approaches between these two extremes are also possible (e.g.
+use the thin pointer representation, but associate an implicit parameter
+with formal parameters). Note also that the thin/fat implementation decision
+is orthogonal to the decision about whether to store the details of how
+a type implements an interface (hereafter referred to as an
+"interface implementation descriptor") as a new dispatch table, as a
+slot-to-slot map, or in some other form.
+
+In any case, a dispatch table could contain a map of some kind (e.g. an array)
+mapping interface type tag values to these "interface implementation
+descriptors", with one entry in the map for each interface implemented by the
+type. This would meet the aforementioned need for a mapping from the tag
+of a specific type and the tag of an interface type which it implements
+to the corresponding interface implementation descriptor.
+
+Contrary to earlier discussions, an interface-to-interface view conversion
+requires no special support. The tag of the source object is that of a
+spcific type and so what is really being implemented is a
+specific-to-interface view conversion, the only added wrinkle being that the
+specific type is not known statically.
 
 ----
 
-1) The compatibility rules for membership testing could be tightened to
-   filter out more cases where the result of a membership test could not
-   possibly be True. The two types could be required to agree with respect to
-   limitedness, accessibility level, and/or set of enclosing generic bodies
-   (with a recheck generic spec rule as well). Do we want all this in a
-   name resolution rule? I'd say no.
+Random notes:
 
-2) "Potentially share descendants" seems like an awkward term.
-    How about "weakly compatible"? "Potentially intersecting"?
-    "Potentially convertible"? The idea here is that we want to allow any
-    membership tests where the answer is not known statically. This includes
-    a case like
-
-       type T1 is tagged null record;
-       type T2 is interface;
-
-       X1 : T1'Class := ... ;
-       X2 : T2'Class := ... ;
-
-       Flag : Boolean := (X1 in T2'Class) and (X2 in T1'Class);
-
-   because of the possibility of a type which is descended from both
-   T1 and T2, e.g.
-       type T3 is new T1 and T2 with null record;
-   .
-
-3) It might be possible to express the legality rules for type conversions more
-   concisely. Would it be equivalent to replace the 3 listed conditions with
-            - The operand type descended from the target type; or
-            - The operand and target types shall potentially share descendants.
-   ?
-
-4) What representation attributes does an interface type have?
-   Can values for these attributes be specified?
-   What do T'Size and T'Alignment mean for any abstract type, not
-   just for interface types?
-
-5) Although an interface type which has an interface parent "is derived from"
-   that type, it is not "a derived type".
-
-6) Inherited homographs must be overridden. If the homographs are
+1) Inherited homographs must be overridden. If the homographs are
    not mode-conformant, then this may be impossible. Life's hard.
 
-7) Nothing here (in particular, nothing in the 8.3 stuff) is intended to
+2) Nothing here (in particular, nothing in the 8.3 stuff) is intended to
    change the semantics of a program which declares no interface types.
 
-8) An example to illustrate some of the 8.3 stuff:
+3) An example to illustrate some of the 8.3 stuff:
 
            package P1 is
                type T1 is interface;
@@ -361,13 +220,11 @@
        copies of your parent's ops hide inherited copies of your grandparent's
        ops" rule.
 
-9) Yes, it really is illegal if the parent type of a "with private"
-   type's completion happens to be descended from some interface that the
+4) Yes, it really is illegal if the parent type of a private extension's
+   completion happens to be descended from some interface that the
    private view was not descended from. This may turn out to be a pain.
 
-   Relaxing the rule that a partial view must be derived from the same
-   interfaces as the completion is derived from is not out of the question, but
-   it could open the door for some very peculiar situations. If this example,
+   This rule is, unfortunately, necessary. If this example,
 
         package P is
           packge Pkg is
@@ -409,77 +266,77 @@
    bodies would be executed. The two conversions to Pkg.Ifc'Class
    would map Pkg.Foo to different slots in the same dispatch table
    because the source types of the conversions are different.
-
-
---------
-
-In defining interface types, a couple of design decisions seem to be
-of interest.
-
-First, there is the question of whether interface types should
-be a whole new class of type or a special kind of abstract tagged
-type. Since interface types have to abide by all of the restrictions
-of an abstract tagged type, the former approach would have involved
-a lot of repetition. The latter approach was chosen.
-
-Second, there is the question of derivation and operator inheritance.
-If a type "implements" an interface, then it must inherit operators
-from the interface type in order to override them. In an earlier version
-of this AI, the "implementing" type was not considered to be derived from the
-parent interface type and operator inheritance was accomplished via
-a separate mechanism. Now, a type which implements an interface type
-is defined to be derived from the interface type, thereby simplifying the
-operator inheritance rules and the definitions of terms such as
-"ancestor", "descendant", and "cover". This means that a given type may
-be immediately derived from more than one type, but at most one of them
-can be a non-interface type. It is no longer the case that every type
-has an "ultimate ancestor", but the term remains well-defined in all the
-cases where it is used in the reference manual.
-
-The rules for type conversion and membership testing need revision to
-cope with the possibility that an interface type and a tagged type
-might have a common descendant even though statically available information
-suggests no relationship between the two types.
-
-As an implementation model, one can think of a type which
-inherits operations from an interface type as defining a
-mapping from the primitive operations of the interface type (perhaps
-represented as dispatch table slot numbers) to those of the inheriting type.
-A dispatching call to an operation of an interface type is than accomplished
-by mapping the the called operation to the corresponding
-operation of the controlling operand's type. Alternatively, one
-might construct a separate dispatch table representing this
-alternative "view" of the "real" dispatch table, but that would
-require more work when deriving from a type which implements
-an interface. The slot-to-slot mapping remains valid and can be
-reused for the derived type, whereas a new alternative "view"
-of the dispatch table of the derived type would need to be
-constructed. A value of type Some_InterFace_Type'Class can then
-be represented at runtime as a record address paired with a
-reference to this dispatch table permutation map.
-
-Classwide streaming operations for interface types require
-some care. Consider the case of a call to Some_Interface_Type'Class'Input
-occuring as the controlling operand of a dispatching call. The
-implementation must be able to determine where to dispatch to in this case.
-Membership testing may also require maintaining additional information
-at runtime.
 
-It is intended that a type which is derived from an interface type should
-inherit the same subprograms as a type which is derived from both the
-interface type and an ancestor of the interface type. The two type definitions
-should be indistinguishable, in the sense that adding or deleting the
-explicit redundant derivation relationship should be a semantics-preserving
-transformation.
+   We want to prevent this sort of thing.
 
-It is intended that there should be no real difference between the two
-forms of derivation from interface type parents. For example, replacing
-the declaration
-   type T is new Interface_Type_1 and Interface_Type_2 with null record;
-with
-   type T is new Interface_Type_2 and Interface_Type_1 with null record;
-should be semantics-preserving.
+5) A type derived from an interface type should inherit the same subprograms
+   as a type which is derived from both the interface type and an ancestor of
+   the interface type. The two type definitions should be indistinguishable,
+   in the sense that adding or deleting the explicit redundant derivation
+   relationship should be a semantics-preserving transformation.
+
+6) It is intended that there should be no real difference between the two
+   forms of derivation from interface types. For example, replacing
+   the declaration
+       type T is new Interface_Type_1 and Interface_Type_2 with null record;
+   with
+       type T is new Interface_Type_2 and Interface_Type_1 with null record;
+   should be semantics-preserving.
 
+7) Someone asked why an interface type declared in a visible part is not
+   allowed to have primitive operations declared in the private part.
+   A dispatching call to a primitive of an interface type will execute
+   the body of a corresponding routine associated with the specific type
+   of the controlling operand. Without this restriction, it is possible that
+   the specific type might provide no such routine. It would be ok to follow
+   the example of 3.9.3(10) and allow this in the case where the subprogram
+   declared in the private part "is overriding an abstract subprogram
+   implicitly declared in the visible part", but this doesn't seem to be
+   worth the bother because this could only be used to override an abstract
+   procedure with a null procedure. There does not appear to be universal
+   agreement on this point.
+
+8) Someone asked why a limited interface cannot be implemented by a
+   non-limited type. An implementation would no longer know statically
+   whether a dispatching function call is a call to a function with a
+   return-by-reference result. This could be implemented, but it seems
+   like an unnecessary complication. The language has, as a matter of
+   general principle, steered away from constructs which would allow a
+   limited view of an object of a non-limited tagged type.
+
+9) It is intended that in the case where the implementation
+   arbitrarily chooses one overrider from among a group of inherited
+   subprograms, users should be unable to determine which
+   member was chosen. The "arbitrarily choose an overrider"
+   monkey business is needed in order to allow
+
+      package Outer is
+        package P1 is
+           type Ifc1 is interface;
+           procedure Null_Procedure (X : Ifc1) is null;
+           procedure Abstract_Subp  (X : Ifc1) is abstract;
+         end P1;
+
+         package P2  is
+           type Ifc2  is interface;
+           procedure Null_Procedure (X : Ifc2) is null;
+           procedure Abstract_Subp  (X : Ifc2) is abstract;
+         end P2;
+
+         type T is new P1.Ifc1 and P2.Ifc2;
+      end Outer;
+
+    without requiring that T explicitly override any of its inherited
+    operations. If requiring explicit overrides in this case is considered
+    to be ok, then that bit of oddness could be deleted from 8.3.
+
+    If it turns out that users can somehow determine which
+    member was chosen and that this approach introduces serious portability
+    problems, then one could impose an arbitrary-but-determininistic
+    tie-breaking scheme (e.g. make use of the order of the interface types,
+    prefering operators inherited from "earlier" types; in the above
+    example, this would mean that the operators inherited from P1.Ifc1
+    would override those inherited from P2.Ifc2).
 
 !example
 
@@ -551,13 +408,64 @@
    P2.Op (P2.Ifc2'Class (X));
  end;
 
-!wording
+ --------
+
+ A somewhat less artificial example:
+
+     package Object_Monitoring is
+       type Monitored_Object is interface;
+       procedure Display (Object : Monitored_Object) is abstract;
+
+       type Object_Reference is access all Monitored_Object'Class;
+       for Object_Reference'Storage_Size use 0;
+
+       procedure Register   (Object : Object_Reference);
+       procedure Unregister (Object : Object_Reference);
+       procedure Display_Registered_Objects;
+     end;
+
+     package body Object_Monitoring is
+       package Object_Reference_Sets is new ... ;
+
+       Registered_Objects : Object_Reference_Sets.Set;
+
+       procedure Display_One (Object : Object_Reference) is
+       begin
+         Display (Object.all);
+       end;
+
+       procedure Display_Registered_Objects is
+       begin
+          Object_Reference_Sets.Visit_All
+            (The_Set   => Registered_Objects,
+             Visit_One => Display_One'Access);
+       end;
+
+       ...
+     end Object_Monitoring;
+
+     package Pkg1 is
+        ...
+     end Pkg1;
+
+     with Object_Monitoring;
+     package body Pkg1 is
+         type T is tagged record F1, F2 : Integer; end record;
 
-In 3.1 add
+         type Monitored_T is new T and Object_Monitoring.Monitored_Object
+             with ...;
 
-    basic_declaration ::= ... | null_procedure_declaration
+         procedure Display (Object : Monitored_T) is begin ... end;
 
+         X : aliased Monitored_T;
 
+         ...
+      begin
+         Object_Monitoring.Register (X'access);
+      end;
+
+!wording
+
 3.2.1 Type Declarations
 
 Add to syntax
@@ -578,14 +486,12 @@
 
 
 Add at the end of paragraph 3:
-
-    A derived type has a parent type and zero or more interface parent types.
-
 
+    A derived type has one parent type and zero or more interface ancestor types.
 
 Replace paragraph 8 with:
 
-    Each class of types that includes the parent type or an interface parent
+    Each class of types that includes the parent type or an interface ancestor
     type also includes the derived type.
 
 Add after paragraph 25:
@@ -594,20 +500,23 @@
     the declared type inherits any user-defined primitive subprograms of the
     interface type in the same way.
 
-    Note: this includes some declarations of non-derived types.
+Add after paragraph 35 (in the Notes section):
 
+    18 An interface type which has an interface ancestor "is derived from"
+    that type, but it is not "a derived type". Conversely, a derived
+    type is never an interface type.
 
 3.4.1 Derivation Classes
 
 Insert after the first sentence of paragraph 2:
 
      A derived type or interface type is also derived from each of its
-     interface parent types, if any.
+     interface ancestor types, if any.
 
 Replace the last sentence of paragraph 10 with:
 
     The ultimate ancestor of a type is the ancestor of that type, if any, that
-    is not a descendant of of any other type and that is not an interface
+    is not a descendant of any other type and that is not an interface
     type (see 3.9.4).
 
 
@@ -628,8 +537,7 @@
 
         An interface type is an abstract tagged type intended for use
         in providing a restricted form of multiple inheritance.
-        A tagged type may be derived from multiple interface types, thereby
-        allowing multiple views of objects of the type.
+        A tagged type may be derived from multiple interface types.
 
                                  Syntax
 
@@ -670,17 +578,18 @@
 
 4.5.2  Relational Operators and Membership Tests
 
-                                Name Resolution
+    Replace paragraph 3 with
 
-        Two types are said to "potentially share descendants" either if one
-        covers the other or if both are class-wide and the corresponding
-        specific type associated with at least one is an interface type.
-
-        The simple_expression shall resolve to be of a type that potentially
-        shares descendants with the tested type.
+        The tested type of a membership test is the type of the range or the
+        type determined by the subtype_mark. If the tested type is tagged,
+        then the simple_expression shall resolve to be of a type that is
+        convertible (see 4.6) to the tested type; if untagged, the expected
+        type for the simple_expression is the tested type.
 
 4.6 Type Conversions
 
+    Replace paragraphs 21-23 with
+
         If the target type is tagged then either:
 
             - The operand type shall be covered by or descended from the target
@@ -689,13 +598,14 @@
             - The operand type shall be a class-wide type that covers the
               target type; or
 
-            - The operand and target types shall potentially share descendants.
+            - The operand and target types shall both be class-wide types and
+              the specific type associated with at least one of them shall
+              be an interface type.
 
         If the target type is not included in any of the above five cases,
         there shall be a type that is an ancestor of both the target type
         and the operand type.
 
-
 6.1  Subprogram Declarations
 
 Replace
@@ -707,23 +617,6 @@
    subprogram_specification ::= procedure_specification
 
 
-6.7  Null Procedures
-
-                              Syntax
-
-    null_procedure_declaration ::= procedure_specification IS NULL;
-
-                              Static Semantics
-
-    A null_procedure_declaration declares a null procedure.
-
-                              Dynamic Semantics
-
-    The execution of a null procedure is invoked by a subprogram call.
-    The execution of the subprogram_body of a null procedure has no
-    effect.
-
-
 7.3 Private Types and Private Extensions
 
     Replace
@@ -741,8 +634,8 @@
 
     Add after paragraph 12:
 
-        An implicit declaration of an inherited subprogram which is neither
-        abstract nor a null procedure overrides that of a subprogram
+        An implicit declaration of an inherited subprogram which is inherited
+        from a non-interface type overrides that of a subprogram
         inherited from an interface type which is implicitly
         declared at the same point.
 
@@ -756,15 +649,19 @@
         declared at the same point, then the subprogram corresponding to the
         inherited subprogram overrides the other inherited subprogram.
 
+        If a descendant of an interface type inherits two or more
+        fully conformant abstract or null subprograms which are
+        implicitly declared at the same point, and if the preceding rules
+        do not cause any of them to be overridden, then one of these
+        subprograms overrides the others; which one is unspecified, except
+        that an abstract subprogram shall not be chosen if a null subprogram
+        is available.
 
     Add after paragraph 26:
 
         If a descendant of an interface type inherits two homographs
-        which are implicitly declared at the same point, then both shall
-        be overridden.
-
-        Note: this requirement may be impossible to satisfy if the homographs
-        are not mode-conformant.
+        which are implicitly declared at the same point, then at least one
+        shall be overridden.
 
 12.5 Formal Types
 
@@ -3483,9 +3380,6 @@
 
 =======================================================================
 
-From: Pascal Leroy
-Sent: Monday, June 16, 2003  2:10 AM
-
 Added for ARG:  Notice that if I make List_View.List an explicit
 interface derived from Lists.List or more properly from an instance of
 Lists.Lists, let's call in My_List, there will be a problem.  I get a
@@ -3504,6 +3398,9 @@
 
 ****************************************************************
 
+From: Pascal Leroy
+Sent: Monday, June 16, 2003  2:10 AM
+
 > Added for ARG:  Notice that if I make List_View.List an explicit
 > interface derived from Lists.List or more properly from an instance of
 
@@ -3535,6 +3432,75 @@
 In fact, I was not too excited about the Object.Operation notation, but
 I find this case quite compelling, as the programmer is relieved from
 having to find the "right" package.
+
+****************************************************************
+
+From: Stephen W Baird
+Sent: Tuesday, September 2, 2003  4:02 PM
+
+This version of AI-251 reflects the feedback of the Toulouse meeting.
+
+Changes include:
+    1) Null procedures are no longer defined in this AI; they have their
+       own AI now.
+    2) Subprogram overriding rules are revised.
+    3) Membership test legality rules are defined in terms of
+       convertibility.
+    4) The term "interface ancestor" replaces the term "interface
+       parent".
+    5) The discussion section and the examples are updated.
+
+[This is version /08 of the AI - ED]
+
+****************************************************************
+
+From: Robert I Eachus
+Sent: Tuesday, September 2, 2003  8:45 PM
+
+Stephen W Baird wrote:
+
+>        A descendant of an interface type shall be limited if and only
+>        if the interface type is limited.
+
+I want to be sure I understand this rule and how it interacts with
+generic instantiation.  It is currently common to define a generic with
+a limited type parameter, if the generic does not depend on assignment
+or equality for the type.  I'm worried about the "only if:" part of the
+rule here.  Can a decendant of an interface type be passed as a generic
+formal parameter of a limited type?
+
+The problem case of course is if the generic actually derives a type
+from the generic parameter:
+
+generic
+   type Foo is limited private;
+   ..
+package Bar is
+
+   type Foobar is new Foo...;
+   ...
+   function Foob return Foobar;
+
+end Bar;
+
+package My_Bar is new Bar(Foo:
+Some_Non_Limited_Type_Descended_From_An_Interface);
+
+But according to your explanation:
+
+8) Someone asked why a limited interface cannot be implemented by a
+   non-limited type. An implementation would no longer know statically
+   whether a dispatching function call is a call to a function with a
+   return-by-reference result. This could be implemented, but it seems
+   like an unnecessary complication. The language has, as a matter of
+   general principle, steered away from constructs which would allow a
+   limited view of an object of a non-limited tagged type.
+
+There should be no problem, because in the instance, type Foobar will be
+non-limited if Some_Non_Limited_Type_Descended_From_An_Interface is also
+non-limited.  So even if an object of type Foobar is passed to some classwide
+operation for Some_Non_Limited_Type..., or one of its parents, there should be
+no problem.
 
 ****************************************************************
 

Questions? Ask the ACAA Technical Agent