CVS difference for ais/ai-00251.txt

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

--- ais/ai-00251.txt	2004/04/06 19:57:01	1.20
+++ ais/ai-00251.txt	2004/05/29 00:38:34	1.21
@@ -1,4 +1,4 @@
-!standard 03.04    (02)                            04-03-29  AI95-00251/12
+!standard 03.04    (02)                            04-05-27  AI95-00251/13
 !standard 02.09    (03)
 !standard 03.02.01 (02)
 !standard 03.04    (03)
@@ -37,10 +37,10 @@
 
 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. Dispatching calls through the primitives of the
-interface type dispatch to code bodies associated with specific tagged types
-that are derived from the interface.
+derived from one or more such interfaces as well as possibly from one tagged
+type; this provides a limited form of multiple inheritance. Dispatching calls
+through the primitives of an interface dispatch to code bodies associated
+with specific tagged types that are derived from that interface.
 
 This proposal also clarifies that it is always legal to convert between two
 types if they have a common ancestor and they meet the restrictions of
@@ -50,13 +50,14 @@
 
 A number of recent language designs have adopted a compromise between full
 multiple inheritance and strict single inheritance, using a concept called
-"interface" types. An interface consists solely of a set of operation specs --
-the interface type has no data components and no operation implementations.
-
-A type may "implement" multiple interfaces, but inherit code from only one
-parent type. This compromise has been found to have much of the power of
-multiple inheritance, without most of the implementation and semantic
-difficulties. This allows a single type to "masquerade" as a number of
+"interface" types. An interface consists solely of a set of operation
+specifications -- the interface type has no data components and no operation
+implementations.
+
+In these designs a type may "implement" multiple interfaces, but can inherit
+code from only one parent type. This compromise has been found to have much of
+the power of multiple inheritance, without most of the implementation and
+semantic difficulties. This allows a single type to "masquerade" as a number of
 different types so that it may take advantage of existing abstractions that
 expect an object that provides a certain set of primitives.
 
@@ -68,64 +69,128 @@
 receive notification when the observed object changes. This is not amenable to
 a generic mix-in approach. You can't mix-in the ability to be on a linked list
 of observers. Access discriminants can accomplish this, at the expense of
-making the type limited, and requiring a fair amount of mechanism. Finally,
-interfacing with Java and the new ".net" infrastructure from Microsoft would be
-significantly smoother if this concept were supported in a natural way in Ada.
+making the type limited, and requiring a fair amount of mechanism. These
+problems would be overcome by Ada adopting the interface concept in some way.
+Moreover, this would make interfacing with Java and the new ".net"
+infrastructure from Microsoft would be significantly smoother.
 
 !proposal
+
+An interface type is a kind of abstract tagged type without any components.
+All primitive subprograms must be abstract or null. (A null procedure is
+introduced by AI-348 and behaves as if it had a body consisting solely of a
+null statement.) So we might have
+
+   package PkgI1 is
+      type I1 is interface;
+      procedure P (X: I1) is abstract;
+      procedure Q (X: I1) is null;
+   end PkgI1;
+
+We can now derive a tagged type from one or more interface types plus
+possibly one tagged type. In other words we can derive a tagged type from
+several other types (its ancestor types) but only one of these can be a
+normal tagged type (it has to be written first). If we have an existing
+normal tagged type T1 in a package PkgT1 with operations P1, P2 and so on we
+could now write
+
+   with PkgI1, PkgT1;
+   package PkgDT is
+      type DT is new PkgT1.T1 and PkgI1.I1 with ...;
+      procedure P(X: DT);
+     --  possibly other ops of DT
+   end PkgDT;
+
+We must of course provide a concrete procedure for P inherited from the
+interface I1. We could also provide an overriding for Q but if we don't then
+we simply inherit the null procedure of I1. We could also override the
+inherited operations P1 and P2 from T1 in the usual way.
 
-An interface type is a new kind of componentless abstract tagged type,
-e.g.
+We can also derive a new interface from other interfaces thus
 
-    package Pkg1 is
-      type T1 is Interface;
-      procedure P (X : T1) is abstract;
-    end Pkg1;
-
-In addition to normal linear (i.e. single parent) derivation, a tagged type
-may now be derived from zero or more interface types, thereby inheriting
-their primitive subprograms, e.g.
-
-    with Pkg1;
-    with Some_Package;
-    package Pkg2 is
-      type T2 is new Some_Package.Some_Tagged_Type and Pkg1.T1 with null record;
-      procedure P (X : T2);
-    end Pkg2;
-
-The primitive subprograms of an interface type must either be abstract
-or "null" (See AI-348 for the definition of null procedures).
-
-The class-wide type corresponding to an interface type covers all of the
-types derived from that interface type:
-
-    with Pkg1, Pkg2;
-    package Pkg3 is
-      type T1_Ref is access all Pkg1.T1'Class;
-      T2_Var : aliased Pkg2.T2;
-      Ref : T1_Ref := T2_Var'Access;
-    end Pkg3;
-
-This also allows conversion between the classwide type and any type which is
-derived from the interface type.
-
-In previous discussions (and in the discussion of the problem, above),
-there have been references to a specific type "implementing" an interface
-type. In this sense, a specific type can be thought of as "implementing"
-an interface if it is derived from that interface.
-This terminology ("implementing an interface") is not used in the RM wording,
-but it is useful for purposes of discussion.
-
-A private extension may be derived from an interface type as well; the
-complete view and the partial view of a type must agree with respect to
-the set of interfaces they "implement".
+   type I1 is interface;
+   ...
+   type I2 is interface;
+   ...
+   type I3 is interface I1;
+   ...
+   type I4 is interface I1 and I2;
+   ...
 
-Formal interface types are added to the language.
+When we derive interfaces in this way we can add new operations so that the
+new interface such as I4 will have all the operations of both I1 and I2 plus
+possibly some others declared specifically as operations of I4. All these
+operations must be abstract or null and there are fairly obvious rules
+regarding what happens if two or more of the ancestor interfaces have the
+same operation. Thus a null operation overrides an abstract one.
 
-See the Wording section for details.
+More generally if we have tagged types T1, T2 and so on we can derive
+further tagged types thus
 
+   type DT1 is new T1 and I1 and I2 with null record;
+                --  no additional components
+   ...
+   type DT2 is new I3 and I4 with record ... end record;
+                --  has additional components
+   ...
+
+The first in the list of ancestor types is always known as the parent type.
+The parent type might or might not be an interface. All other ancestor types
+must be interfaces. Thus the following is not permitted
+
+   type DT3 is new T1 and T2 with ....       -- illegal
+
+Class-wide types also apply to interface types. The class-wide type I1'Class
+covers all the types derived from the interface I1 (both other interfaces as
+well as normal tagged types). We can then dispatch using an object of a
+concrete tagged type in that class in the usual way since we know that any
+abstract operation of I1 will have been overridden. So we might have
+
+   type I1_Ref is access all T1'Class;
+   DT1_Var : aliased DT1;
+   Ref: I1_Ref := DT1_Var'Access;
+
+Observe that conversion is permitted between the class-wide type I1_Ref and
+any type which is derived from the interface type I1. We informally speak
+of a specific tagged type as implementing an interface from which it is
+derived (directly or indirectly). The phrase "implementing an interface" is
+not used in the wording but it is useful for purposes of discussion.
+
+Interfaces can also be used in private extensions and as generic parameters.
+Thus
+
+      type PT1 is new T1 and I2 and I3 with private;
+      ...
+   private
+      type PT1 is new DT1 and I2 and I3 with null record;
+
+An important rule regarding private extensions is that the full view and the
+partial view must agree with respect to the set of interfaces they
+implement. Thus although the parent in the full view need not be T1 but can
+be any type derived from T1, the same is not true of the interfaces which
+must be such that they both implement the same set exactly.
+
+Generic parameters take the form
+
+   generic
+      type FI is interface I1 and I2;
+   package...
+
+and then the actual parameter must be an interface which implements all the
+ancestors I1, I2 etc. The formal could also just be "type FI is interface;"
+in which case the actual parameter can be any interface. (There might be
+subprograms passed as further parameters which would require that the actual
+has certain operations.)  The interfaces I1 and I2 might themselves be
+formal parameters occuring earlier in the parameter list.
+Interfaces can also be limited.
+
 !wording
 
+In 2.9(3) as modified by AI-284 add the following to the list of nonreserved
+keywords
+
+       interface
+
 3.2.1 Type Declarations
 
 Add to syntax
@@ -193,11 +258,11 @@
 
 3.9.4 Interface Types
 
-    This section is entirely new.
+    (This section is entirely new.)
 
-        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.
+        An interface type is an abstract tagged type which provides a
+	restricted form of multiple inheritance. A tagged type may be derived
+	from multiple interface types.
 
                                  Syntax
 
@@ -208,9 +273,11 @@
         An interface type (also called an "interface") is a specific abstract
         tagged type that is defined by an interface_type_definition.
 
-                                 Legality Rules
+        [An interface type has no components.]
 
-        An interface type shall have no components.
+	AARM Note: This follows from the syntax.
+
+                                 Legality Rules
 
         All user-defined primitive subprograms of an interface type shall be
         abstract subprograms or null procedures.
@@ -237,18 +304,19 @@
 	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. We may want to reconsider this if some form of AI-318 is included
-	in the standard. End AARM Note.
+	in the standard.
+        End AARM Note.
 
         A full view shall be a descendant of an interface type if and only if
-        the  corresponding partial view (if any) is also a descendant of the
+        the corresponding partial view (if any) is also a descendant of the
         interface type.
 
 
 	AARM Note:
-	Reason: If this example,
+	Reason: Consider the following example:
 
             package P is
-              packge Pkg is
+              package Pkg is
                   type Ifc is interface;
                   procedure Foo (X : Ifc) is abstract;
               end;
@@ -280,13 +348,13 @@
                  -- call Foo #1
             end P2;
 
-	, were legal (it is illegal because the completion of T1 is descended
-        an interface that the partial view is not descended from), then
-        we would have two dispatching calls to Pkg.Foo with the
-        two controlling operands having the same tag and yet different
-        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.
+	If this example were legal (it is illegal because the completion of T1
+	is descended from an interface that the partial view is not descended
+	from), then we would have two dispatching calls to Pkg.Foo with the two
+	controlling operands having the same tag and yet different 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.
 
         This would be bad.
 	End AARM Note
@@ -354,7 +422,8 @@
 
 8.3 Visibility
 
-Replace paragraphs 9/1 - 13 with
+Add a new bullet into paragraphs 9/1 - 13 (the entire group is given here to
+make it easier to evaluate the changes):
 
     Two homographs are not generally allowed immediately within the same
     declarative region unless one overrides the other (see Legality Rules
@@ -406,6 +475,7 @@
 
 	    without requiring that T explicitly override any of its inherited
 	    operations.
+        End AARM Note
 
       * For an implicit declaration of a primitive subprogram in a generic unit,
         there is a copy of this declaration in an instance. However, a whole new
@@ -448,7 +518,7 @@
 
     Add to syntax
 
-        formal_type_declaration ::= ... | formal_interface_type_definition
+        formal_type_definition ::= ... | formal_interface_type_definition
 
 
 
@@ -470,7 +540,7 @@
 
 12.5.5 Formal Interface Types
 
-    This section is entirely new.
+    (This section is entirely new.)
 
         The class determined for a formal interface type is the class of all
         interface types.
@@ -496,7 +566,7 @@
 
 13.14 Freezing Rules
 
-    Add after paragraph 7:
+    Add a further bullet after paragraph 7:
 
         The declaration of a specific descendant of an interface type freezes
         the interface type.
@@ -505,19 +575,48 @@
 
 All primitives of an interface are required to be abstract or null to minimize
 difficulty in resolving what happens when the "same" primitive is inherited
-from two interfaces, or from an interface and the parent type. If only the
-parent type can have a non-abstract, non-null primitive, no question arises
-as to which implementation to use. Languages that support full multiple
-inheritance need elaborate rules for resolving these kinds of conflicts.
-
-No data components are allowed in interfaces to avoid implementation complexity
-and inefficiency. If data components could be inherited from multiple
-interfaces, or from an interface and the parent type, then the offset of a
-component of an interface could not be determined statically. It would make
-component access as complicated and expensive as calling a primitive (which is
-discussed below), or require recompilation of inherited primitives even when
-not overridden. Inheritance then becomes more like macro expansion.
+from two (or more) ancestor types. If only one ancestor type is permitted to
+have non-abstract, non-null primitives, no question arises as to which
+implementation to use. For simplicity the first type in the list of ancestor
+types is called the parent type and this parent type is the only ancestor that
+can be a normal tagged type - note that the parent type can itself be an
+interface type. Languages that support full multiple inheritance need elaborate
+rules for resolving these kinds of conflicts and lead to confusion in the mind
+of user.
+
+Moreover, no data components are allowed in interfaces to avoid implementation
+complexity and inefficiency. If data components could be inherited from
+multiple ancestors, then the offset of a component of an interface could not be
+determined statically. It would make component access as complicated and
+expensive as calling a primitive (which is discussed below), or require
+recompilation of inherited primitives even when not overridden. Inheritance
+then becomes more like macro expansion.
+
+We considered avoiding the introduction of the new concept of an interface
+type by simply permitting inheritance from several tagged types provided
+only one had concrete operations and components. However, this approach
+would prevent the clean introduction of the interface concept into generics,
+and would be fragile: if a maintenance programmer added a component or concrete
+operation, other, possibly distant, code would become illegal. Moreover, this
+is probably less easy for the user to understand - particularly if the user is
+familiar with Java.
+
+Having decided that a new concept was required, many forms of syntax were
+considered. The new keyword interface was chosen as best reflecting the
+nature of the concept. However, it was recognized that Interface is probably
+a popular identifier and that to make it a reserved word would cause
+irritation among the user community. Thus the concept of keywords was
+introduced (see Ai-284). Keywords cover all the existing reserved words and
+these remain reserved but unreserved keywords are now also permitted.
+Confusion between their use as keywords and use as identifiers is avoided by
+ensuring that unreserved keywords are only used in syntactically clear
+situations.
+
+Observe that the keyword interface is always followed by a list of interface
+identifiers but that this list may be null. Thus "interface" may be followed
+just by a semicolon or by the identifier of an interface.
 
+
 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
@@ -529,30 +628,34 @@
 for the corresponding operations, there is no good way to prevent
 these operations from being unintentionally overridden outside of
 the package by a descendant that explicitly implements the same
-interface.  For example:
+interface.
 
-    package P is
-        type T1 is tagged private;
-       ...
-    private
-        type T1 is new Foo and I with ...
-        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
-        -- will override operations associated with T1's "private"
-        -- inheritance of I, violating the "privateness" of the
-        -- inheritance.
+For example if I1 is an interface type with a primitive P and T1 is some
+tagged type as in the proposal section then we might otherwise write
 
-In the above case, the partial view of T1 could be:
+   package Pkg1 is
+      type PT1 is tagged private;
+      ...
+   private
+      type PT1 is new T1 and I1 with ...
+                             -- illegal private inheritance of interface
+      procedure P(X: PT1);   -- overrides primitive P of interface I1
+   end Pkg1;
 
-    type T1 is new I with private;
+   ...
+   type PT2 is new Pkg1.PT1 and I1 with ...
+   procedure P(X: PT2);
+      -- if primitive operations such as P of I1 are overridden for PT2,
+      -- they will override operations associated with PT1's private
+      -- inheritance of I1, violating the privateness of the inheritance.
+
+In the above case, the partial view of PT1 is allowed to be
+
+   type PT1 is new I1 with private;
+
+This makes it visible that the interface I1 is inherited and thus that its
+primitives might well be overriden outside Pkg1.
 
-This would make it visible that I is inherited, and thereby marking
-the primitives of "I" as fair game for overriding outside P.
 
         Possible Implementation Model
 
@@ -575,16 +678,16 @@
 table permutation map.
 
 Consider the example of a call to Some_Interface_Type'Class'Input
-occuring as the controlling operand of a dispatching call. The
+occurring 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
+reference to the associated dispatch table permutation map (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.
+could be represented as an unaugmented 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
@@ -624,13 +727,14 @@
 1) Inherited homographs must be overridden. If the homographs are
    not mode-conformant, then this may be impossible. Life's hard.
 
-2) Nothing here (in particular, nothing in the 8.3 stuff) was *intended* to
-   change the semantics of a program which declares no interface types.
+2) Nothing here (in particular, nothing in the changes to the visibility rules
+   in 8.3) was *intended* to change the semantics of a program which declares
+   no interface types.
 
    Consider, however:
         generic
-          type T1 is private;
-          type T2 is private;
+            type T1 is private;
+            type T2 is private;
         package G is
             type T is null record;
             procedure P (X : T; Y : T1);
@@ -641,7 +745,8 @@
 
         type D is new I.T; -- formerly legal, now illegal.
 
-   Disallowing this case does not seem like a bad thing, but it is a change.
+   Disallowing this case does not seem like a bad thing, but it is a
+   (very minor) change.
 
 3) 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
@@ -657,17 +762,17 @@
        type T is new Interface_Type_2 and Interface_Type_1 with null record;
    should be semantics-preserving.
 
-5) Someone asked why an interface type declared in a visible part is not
+5) Note that 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.
+   the specific type might provide no such routine. It would be OK to follow
+   the example of the rules in 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.
 
 
 The changes to section 4.6 also include a solution for the problem originally
@@ -711,10 +816,10 @@
 
 As seen from the point of the type conversion, Target is a numeric type
 although Source is not. With the original wording, 4.6(21-23) does not
-apply and the conversion is would be illegal.
+apply and the conversion would be illegal.
 
-Thus, the Standard as as written is incompatible with Ada 83, which
-allowed conversions between any two type related by derivation. Certainly
+Thus, the Standard as written is incompatible with Ada 83, which
+allowed conversions between any two types related by derivation. Certainly
 no such incompatibility was intended; no such incompatibility is listed
 under the "Incompatibilities with Ada 83" heading in the AARM.
 
@@ -769,8 +874,7 @@
       ...
    end P2;
 
-   type D is tagged
-       with P1.Ifc1 and P2.Ifc2 and
+   type D is new P1.Ifc1 and P2.Ifc2 with
        record
            F1, F2 : Integer;
        end record;
@@ -928,12 +1032,12 @@
 !corrigendum 3.4(35)
 
 @dinsa
-17  If the reserved word @b<abstract> is given in the declaration of a type,
-the type is abstract (see 3.9.3).
+@xindent<@s9<17  If the reserved word @b<abstract> is given in the declaration
+of a type, the type is abstract (see 3.9.3).>>
 @dinst
-18  An interface type which has an interface ancestor "is derived from"
-that type, and therefore is a derived type. A @fa<derived_type_definition>,
-however, never defines an interface type.
+@xindent<@s9<18  An interface type which has an interface ancestor "is derived
+from" that type, and therefore is a derived type. A
+@fa<derived_type_definition>, however, never defines an interface type.>>
 
 !corrigendum 3.4.1(02)
 
@@ -971,7 +1075,7 @@
 type @i<T1> if @i<T2> is a descendant of @i<T1>. Similarly, the universal types
 are defined to be descendants of the root types of their classes. If a type
 @i<T2> is a descendant of a type @i<T1>, then @i<T1> is called an @i<ancestor>
-of @i<T2>. The @i<ultimate ancestor> of a type is an ancestor of that type that
+of @i<T2>. An @i<ultimate ancestor> of a type is an ancestor of that type that
 is not a descendant of any other type. Each untagged type has a unique
 ultimate ancestor.
 
@@ -996,9 +1100,9 @@
 !corrigendum 3.9.4(1)
 
 @dinsc
-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.
+An interface type is an abstract tagged type which provides a restricted
+form of multiple inheritance. A tagged type may be derived from multiple
+interface types.
 
 @i<@s8<Syntax>>
 
@@ -1009,9 +1113,9 @@
 An interface type (also called an "interface") is a specific abstract
 tagged type that is defined by an @fa<interface_type_definition>.
 
-@i<@s8<Legality Rules>>
+An interface type has no components.
 
-An interface type shall have no components.
+@i<@s8<Legality Rules>>
 
 All user-defined primitive subprograms of an interface type shall be
 abstract subprograms or null procedures.
@@ -1029,7 +1133,7 @@
 if the interface type is limited.
 
 A full view shall be a descendant of an interface type if and only if
-the  corresponding partial view (if any) is also a descendant of the
+the corresponding partial view (if any) is also a descendant of the
 interface type.
 
 For an interface type declared in a visible part, a primitive
@@ -1501,7 +1605,7 @@
 
 This amendment AI proposes that "abstract interface" types may be
 defined, and that a tagged type may "implement" one or more
-such abstract interfaces.  The classwide type associated with
+such abstract interfaces. The class-wide type associated with
 the abstract interface "covers" all types that implement it.
 Dispatching calls through the primitives of the abstract interface
 type dispatch to code bodies associated with specific tagged types that

Questions? Ask the ACAA Technical Agent