CVS difference for ais/ai-00251.txt

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

--- ais/ai-00251.txt	2001/10/09 00:47:09	1.5
+++ ais/ai-00251.txt	2002/02/07 04:56:42	1.6
@@ -1,11 +1,11 @@
-!standard 03.04    (02)                            01-10-05  AI95-00251/02
+!standard 03.04    (02)                            02-02-05  AI95-00251/03
 !standard 03.09.01 (02)
 !class amendment 00-12-04
 !status work item 00-12-04
 !status received 00-12-04
 !priority High
 !difficulty Hard
-!subject Tagged Types, Abstract Interface, Multiple Inheritance
+!subject Abstract Interfaces to provide Multiple Inheritance
 
 !summary
 
@@ -48,7 +48,7 @@
 
    type_definition ::= ... | abstract_interface_definition
 
-   abstract_interface_definition ::= ABSTRACT [LIMITED]
+   abstract_interface_definition ::= ABSTRACT [LIMITED] INTERFACE
 
    derived_type_definition ::=
      [ABSTRACT] NEW parent_subtype_indication
@@ -71,6 +71,12 @@
      [ABSTRACT] NEW ancestor_subtype_indication
        [AND abstract_interface_list] [WITH PRIVATE];
 
+  NOTE: we plan to make "INTERFACE" an unreserved keyword, to minimize
+  upward incompatibility.  The current term "reserved word" will
+  probably become something like "keyword", which can be either
+  "reserved" or "unreserved."  Most new users need not be aware of
+  the distinction, and will probably treat all keywords as reserved.
+
 An abstract interface type (or "interface" for short) is defined by an
 abstract_interface_definition or by a derived_type_definition where the word
 ABSTRACT appears, the parent type is an interface, and there is no
@@ -81,7 +87,7 @@
 course have them).
 
 All primitive operations of an abstract interface type must be declared
-abstract (or perhaps "is null" -- see below). Only abstract interface types may
+abstract or "is null" (see below). Only abstract interface types may
 be mentioned in an abstract_interface_list.
 
 A tagged type may declare that it "implements" an interface by mentioning it
@@ -130,6 +136,13 @@
 type must be a record extension that implements all of the types implemented by
 the private extension.
 
+A private extension or private tagged type must implement all the
+interfaces implemented by its full view.  In other words, the full
+view may not implement additional "private" interfaces.  This is to
+prevent the descendants of the partial view from unintentionally "stepping"
+on the implementations of the primitive operations of a privately
+inherited interface.
+
 A type that implements (directly or indirectly) an interface inherits the
 interface's (abstract) primitive operations with the usual substitution of the
 new type for the abstract interface type in their profile. If a type inherits
@@ -162,18 +175,46 @@
 from an abstract tagged type to an abstract interface type. Alternatively, a
 normal record aggregate may be used, taking advantage of the fact that the
 parent interface has no components.
+
+        "Null" Primitives
+
+   basic_declaration ::= ... | null_subprogram_declaration
+
+   null_subprogram_declaration ::= subprogram_specification IS NULL;
 
-Note that only dispatching calls are permitted on the primitives of an
-interface, since they are all abstract.
+As part of this proposal we include an ability to declare a
+primitive procedure using "is null" rather than "is abstract."
+This would be permitted for interfaces, as well as other types.
+The semantics of this would be that the body of the procedure is
+defined to be "is begin null; end;".
 
+If an interface has a null (i.e. non-abstract) primitive, then an abstract
+generic formal extension of the interface is only matched by types that have
+non-abstract implementations of this primitive. This allows non-dispatching
+calls on the primitive of the generic formal type to be made inside the
+generic, which may 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.
+
+Upon inheritance, a non-null inherited primitive overrides any null or abstract
+inherited primitives. If one or more null primitives are inherited, and no
+non-null, non-abstract primitives, then the null primitives must all be fully
+conforming (so they have the same formal parameter names and defaults), and the
+resulting inherited primitive is null. And of course, a non-dispatching call
+is permitted on a null, as opposed to abstract, primitive of an interface
+(which is really only useful in generics).
+
+Note that only dispatching calls are permitted on the non-null primitives of an
+interface, since they are necessarily abstract.
+
 !discussion
 
-All primitives of an interface are required to be abstract to avoid any
+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 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.
+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
@@ -191,6 +232,81 @@
 allowed, but hopefully none where abstract private/null-record types are
 permitted, but interfaces are not.
 
+We disallow "private" inheriting from interfaces, because without
+allocating a complete separate set of dispatching operation "slots"
+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:
+
+    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.
+
+In the above case, the partial view of T1 would need to be:
+
+    type T1 is new I with private;
+
+This would make it visible that I is inherited, and thereby making
+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.
+
         Possible Implementation Model
 
 A possible implementation model for an interface "view" of an object is to use
@@ -247,7 +363,7 @@
 rather than a direct pointer to the dispatch table for the interface.
 
 
-	"Thin Pointer" Implementation Model
+        "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.
@@ -262,7 +378,7 @@
 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
+        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
@@ -284,71 +400,33 @@
 or more interfaces would also have to use fat pointers, even though both words
 would point to the same dispatch table.
 
-	Possible "is null" rather than "is abstract" for primitives
-
-A possible addition to this proposal would be to allow primitive procedures of
-interfaces (and other types) to be declared as "is null" rather than "is
-abstract." The semantics of this would be that the body of the procedure is
-defined to be "is begin null; end;". This would then enable certain abstract
-types that have null (non-abstract) default implementations of certain
-primitives to also be converted 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.]
-
-If an interface has a null (i.e. non-abstract) primitive, then an abstract
-generic formal extension of the interface is only matched by types that have
-non-abstract implementations of this primitive. This allows non-dispatching
-calls on the primitive of the generic formal type to be made inside the
-generic, which may 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.
-
-Upon inheritance, a non-null inherited primitive overrides any null or abstract
-inherited primitives. If one or more null primitives are inherited, and no
-non-null, non-abstract primitives, then the null primitives must all be fully
-conforming (so they have the same formal parameter names and defaults), and the
-resulting inherited primitive is null. And of course, a non-dispatching call
-is permitted on a null, as opposed to abstract, primitive of an interface
-(which is really only useful in generics).
-
-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 independent of this proposal for
-interfaces.
-
 !example
 
-	type Stack is abstract; -- An abstract interface type
-	procedure Append (S : in out Stack; E : Elem) is abstract;
-	function Length (S : Stack) return Natural is abstract;
-	procedure Remove_Last (S : in out Stack; E : out Element) is abstract;
-
-	type Queue is abstract; -- Another interface.
-	function Length (Q : Queue) return Natural is abstract;
-	procedure Append (Q : in out Queue; E : Elem) is abstract;
-	procedure Remove_First (Q : in out Queue; E : out Element) is abstract;
-
-	. . .
-	type Deque is abstract new Queue and Stack;
-			-- An interface which inherits from both
-			-- the Queue and Stack interfaces.
-	procedure Prepend (Q : in out Deque; E : Elem) is abstract;
-	procedure Remove_Last (Q : in out Deque; E : out Elem) is abstract;
-
-	. . .
-	type My_Deque is new Deque with private;
-			-- A private extension that implements an interface
+        type Stack is abstract interface; -- An abstract interface type
+        procedure Append (S : in out Stack; E : Elem) is abstract;
+        function Length (S : Stack) return Natural is abstract;
+        procedure Remove_Last (S : in out Stack; E : out Element) is abstract;
+
+        type Queue is abstract interface; -- Another interface.
+        function Length (Q : Queue) return Natural is abstract;
+        procedure Append (Q : in out Queue; E : Elem) is abstract;
+        procedure Remove_First (Q : in out Queue; E : out Element) is abstract;
+
+        . . .
+        type Deque is abstract new Queue and Stack;
+                        -- An interface which inherits from both
+                        -- the Queue and Stack interfaces.
+        procedure Prepend (Q : in out Deque; E : Elem) is abstract;
+        procedure Remove_Last (Q : in out Deque; E : out Elem) is abstract;
+
+        . . .
+        type My_Deque is new Deque with private;
+                        -- A private extension that implements an interface
 private
-	type My_Deque is new Blob and Deque with record
-			-- Conventional type implementing an interface.
-		. . .
-	end record;
+        type My_Deque is new Blob and Deque with record
+                        -- Conventional type implementing an interface.
+                . . .
+        end record;
 
 !ACATS test
 

Questions? Ask the ACAA Technical Agent