CVS difference for ais/ai-00345.txt

Differences between 1.11 and version 1.12
Log of other versions for file ais/ai-00345.txt

--- ais/ai-00345.txt	2004/03/02 04:45:00	1.11
+++ ais/ai-00345.txt	2004/04/06 21:50:50	1.12
@@ -1,4 +1,4 @@
-!standard  3.04.03    (00)                             04-01-25  AI95-00345/04
+!standard  3.04.03    (00)                             04-03-31  AI95-00345/05
 !class amendment 03-08-07
 !status work item 03-09-28
 !status received 03-06-12
@@ -12,23 +12,20 @@
 used as ancestors for protected and task types. The primitive operations
 of these interfaces are inherited by the protected or task type. If the
 operations are declared abstract in the interface, they must be
-overridden in the inheriting type.  The overriding can be performed in
+overridden in the inheriting type. The overriding can be performed in
 the usual way by declaring overriding primitives of the protected or
 task type, or by declaring entries or protected subprograms that
 override the primitive of the interface once it has been transformed
 into a "prefix" notation a la AI-252.
 
-We also propose two language-defined limited interface types,
-tentatively named Task_Interface and Protected_Interface. Neither has
-any primitive operations. Every task type implicitly implements
-Task_Interface; every protected type implicitly implements
-Protected_Interface. "Normal" tagged types are not allowed to be
-derived from these interfaces, so specifying one of these interfaces as
-an ancestor of a user-defined interface type can be used as a way to
-require that the interface be implemented with a task or protected type.
-In addition, an Identity function is added to Ada.Task_Identification
-which takes Task_Interface'Class, and is equivalent to the 'Identity
-attribute, returning the task's ID.
+Rather than declaring an interface "limited," an interface
+may be specified as a "task," "protected," or "synchronized" interface.
+In this case, the interface can only be implemented by, respectively,
+a task type, a protected type, or either a task or protected type.
+
+A class-wide object of an interface type that implements a task
+interface type is a task object, allowing operations such as
+abort, 'Identity, 'Callable, etc. to be applied to it.
 
 !problem
 
@@ -49,17 +46,12 @@
 ("object.operation" notation). We will identify where we are referring to
 AI-251 or AI-252 wording.
 
-Modify 3.4(4):
 
-  Class-wide types
-      Class-wide types are defined for (and belong to) each derivation
-      class rooted at a tagged {or interface} type (see 3.9 {and 3.9.4}) ...
+Modify the first sentence of 3.9.1(1):
 
-Modify 3.9(13):
+    The parent type of a record extension shall not be a class-wide type {nor
+    shall it be a synchronized tagged type (see 3.9.4)}.
 
-    For every subtype S of a tagged {or interface} type T (specific or
-    class-wide), the following attribute is defined:
-
 Replace 3.9.3(1-2) with:
 
     An abstract type is a type intended for use as an ancestor of
@@ -81,22 +73,54 @@
 
   Modify 3.9.4(1):
 
-    An interface type is an abstract [tagged] type intended for use in
-    providing a restricted form of multiple inheritance. A tagged {,
-    task, or protected type, or another interface} type may be derived
-    from multiple interface types.
+    An interface type is an abstract tagged type intended for use in providing
+    a restricted form of multiple inheritance. A tagged {, task, or protected}
+    type may be derived from [multiple] {one or more} interface types.
 
   Change 3.9.4(2) to:
-
-    interface_type_definition ::= [LIMITED] INTERFACE [and interface_list]
 
-In the wording of AI-252:
+    interface_type_definition ::=
+      [LIMITED | TASK | PROTECTED | SYNCHRONIZED] INTERFACE [AND interface_list]
 
-  Modify 4.1.3(9,15):  Change "tagged" to "tagged or class-wide"
+  Add after 3.9.4(3):
 
-  Modify 6.3.1(10): Change "tagged" to "tagged or class-wide"
+     An interface with the reserved word LIMITED, TASK, PROTECTED, or
+     SYNCHRONIZED in its definition is termed, respectively, a *limited
+     interface*, a *task interface*, a *protected interface*, or a
+     *synchronized interface*. In addition, all task and protected interfaces
+     are synchronized interfaces, and all synchronized interfaces are limited
+     interfaces. A view of an object that is of a task interface type (or of a
+     corresponding class-wide type) is a task object. Similarly, a view of an
+     object that is of a protected interface type (or of a corresponding
+     class-wide type) is a protected object.
+
+     A task or protected type derived from an interface is a tagged type. Such
+     a tagged type is called a *synchronized* tagged type, as are synchronized
+     interfaces and private extensions derived from synchronized interfaces.
+
+  Change 3.9.4(8) to:
+
+     A descendant of a nonlimited interface shall be nonlimited. A descendant
+     of a task interface shall be a task type or a task interface. A descendant
+     of a protected interface shall be a protected type or a protected
+     interface. A descendant of a synchronized interface shall be a task type,
+     a protected type, or a synchronized interface.
+
+   AARM Note:
+
+       We require that a descendant of a task, protected, or synchronized
+       interface repeat the explicit kind of interface it will be, rather than
+       simply inheriting it, so that a reader is always aware of whether the
+       interface provides synchronization and whether it may be implemented
+       only by a task or protected type. The only place where inheritance of
+       the kind of interface might be useful would be in a generic if you
+       didn't know the kind of the actual interface. However, the value of
+       that is low because you cannot implement an interface properly if you
+       don't know whether it is a task, protected, or synchronized interface.
+       Hence, we require the kind of the actual interface to match the kind of
+       the formal interface (see 12.5.5).
 
-[end of AI-252-relative modifications]
+ [end of AI-251-relative modifications]
 
 Add after 6.3.1(24):
 
@@ -115,11 +139,12 @@
 Add after 9.1(8):
 
     Each interface_subtype_mark of an interface_list appearing within a
-    task_type_declaration shall denote a limited interface type.
+    task_type_declaration shall denote a limited interface type that
+    is not a protected interface.
 
     If a task_type_declaration includes an interface_list, then for each
-    primtive subprogram inherited by the task type, one of the following
-    shall apply:
+    primitive subprogram inherited by the task type, at most one of the
+    following shall apply:
 
       - the inherited subprogram shall be overridden with a primitive
         subprogram of the task type, in which case the overriding
@@ -127,29 +152,15 @@
         subprogram and not abstract; or
 
       - the first parameter of the inherited subprogram shall be of the
-        task type or an access parameter designating the task type, and
-        there shall be an entry_declaration with the same identifier
-        within the task_type_declaration and either:
-
-          * it shall be for a single entry with a profile that is type
-            conformant with that of the inherited subprogram after
-            omitting this first parameter, or
-
-          * it shall be for a family of entries with entry index type
-            the same as the type of the second parameter of the inherited
-            subprogram and with profile that is type conformant with that
-            of the inherited subprogram after omitting its first two
-            parameters,
-
-        in which case the inherited subprogram is said to be
-        "implemented" by the conforming entry (family), and its profile
-        after omitting the first (and second) parameter shall be subtype
-        conformant with that of the entry (family); or
-
-      - the inherited subprogram shall be a null procedure.
+        task type or an access parameter designating the task type, and there
+        shall be an entry_declaration for a single entry with the same
+        identifier and a profile that is type conformant with that of the
+        inherited subprogram after omitting this first parameter, in which case
+        the inherited subprogram is said to be "implemented" by the conforming
+        entry, and its profile after omitting the first parameter shall be
+        subtype conformant with that of the entry.
 
-    If an inherited subprogram is implemented by an entry family, its
-    second parameter shall be of mode IN.
+    If neither applies, the inherited subprogram shall be a null procedure.
 
 Add after 9.1(9.1/1):
 
@@ -166,47 +177,35 @@
 Add after 9.4(10):
 
     Each interface_subtype_mark of an interface_list appearing within a
-    protected_type_declaration shall denote a limited interface type.
+    protected_type_declaration shall denote a limited interface type that
+    is not a task interface.
 
     If a protected_type_declaration includes an interface_list, then
-    for each primitive subprogram inherited by the protected type, one
-    of the following shall apply:
+    for each primitive subprogram inherited by the protected type, at most
+    one of the following shall apply:
 
       - the inherited subprogram shall be overridden with a primitive
-        subprogram of the protected type, in which case the overriding
+        subprogram of the protected type; in this case the overriding
         subprogram shall be subtype conformant with the inherited
         subprogram and not abstract; or
 
       - the first parameter of the inherited subprogram shall be of the
-        protected type or an access parameter designating the protected
-        type, and there shall be a protected_operation_declaration with the same
-        identifier within the protected_type_declaration and either:
-
-          * it shall be for a protected subprogram or single entry with
-            a profile that is type conformant with that of the inherited
-            subprogram after omitting this first parameter, or
-
-          * it shall be for a family of entries with entry index type
-            the same as the type of the second parameter of the inherited
-            subprogram and with profile that is type conformant with that
-            of the inherited subprogram after omitting its first two
-            parameters,
-
-        in which case the inherited subprogram is said to be
-        *implemented* by the conforming protected subprogram or entry
-        (family), and its profile after omitting the first (and second)
-        parameter shall be subtype conformant with that of the protected
-        subprogram or entry (family); or
-
-      - the inherited subprogram shall be a null procedure.
-
-    If an inherited subprogram is implemented by a protected procedure
-    or entry (family), then its first parameter shall be an
-    access-to-variable parameter, or of mode OUT or IN OUT.  If an
-    inherited subprogram is implemented by an entry family, its second
-    parameter shall be of mode IN.
+        protected type or an access parameter designating the protected type,
+        and there shall be a protected_operation_declaration for a protected
+        subprogram or single entry with the same identifier within the
+        protected_type_declaration, having a profile that is type conformant with
+        that of the inherited subprogram after omitting this first parameter;
+        in this case the inherited subprogram is said to be *implemented* by
+        the conforming protected subprogram or entry, and its profile after
+        omitting the first (and second) parameter shall be subtype conformant
+        with that of the protected subprogram or entry.
+
+    If neither applies, the inherited subprogram shall be a null procedure.
+
+    If an inherited subprogram is implemented by a protected procedure or
+    entry, then its first parameter shall be an access-to-variable parameter,
+    or of mode OUT or IN OUT.
 
-
 Modify 9.4(11):
 
     If a protected_type_declaration includes an interface_list, the
@@ -240,67 +239,108 @@
 
     If a procedure_call_statement is used for a procedure_or_entry_call,
     and the procedure is implemented by an entry, then the procedure_name,
-    or the procedure_prefix and possibly one or two of the parameters of
-    the procedure_call_statement, determine the target object of the call,
-    the entry or entry family, and the entry index, if any.  If the
-    procedure is not implemented by an entry, then the procedure call is
-    equivalent to an entry call on an open entry of a newly created local
-    task whose accept statement invokes the procedure's body.
-
- [AARM Implementation Note: the specified equivalence is intended to
-  ensure that the call remains abortable, with a priority inherited
-  from the invoker, and no delay_alternative, else part, or
-  abortable part of the select_statement is executed.]
-
+    or the procedure_prefix and possibly one of the parameters of
+    the procedure_call_statement, determine the target object of the call
+    and the entry to be called.
+
+Modify 9.7.2(4)
+
+    For the execution of a timed_entry_call, the entry_name{, procedure_name,
+    or procedure_prefix,} and {any} actual parameters are evaluated, as for a
+    simple entry call (see 9.5.3) {or procedure call (see 6.4)}. The expiration
+    time (see 9.6) for the call is determined by evaluating the
+    delay_expression of the delay_alternative. {If the call is an entry call or
+    a call on a procedure implemented by an entry,} the entry call is then
+    issued. {Otherwise, the call proceeds as described in 6.4 for a procedure
+    call, followed by the sequence_of_statements of the entry_call_alternative,
+    and the delay_alternative sequence_of_statements is ignored.}
+
+Modify 9.7.4(4): change "entry_call_statement" to "procedure_or_entry_call"
+
+Modify 9.7.4(6):
+
+    For the execution of an asynchronous_select whose triggering_statement is
+    an [entry_call_statement] {procedure_or_entry_call}, the entry_name{,
+    procedure_name, or procedure_prefix,} and actual parameters are evaluated
+    as for a simple entry call (see 9.5.3) {or procedure call (see 6.4).}[,
+    and] {If the call is an entry call or a call on a procedure implemented by
+    an entry,} the entry call is issued. If the entry call is queued (or
+    requeued-with-abort), then the abortable_part is executed. If the entry
+    call is selected immediately, and never requeued-with-abort, then the
+    abortable_part is never started. {If the call is on a procedure that is
+    not implemented by an entry, the call proceeds as described in 6.4,
+    followed by the sequence_of_statements of the triggering_alternative, and
+    the abortable_part is never started.}
+
+Modify 9.8(3):
 
-Modify 9.7.4(4,6): change "entry_call_statement" to
-    "procedure_or_entry_call"
+    Each task_name is expected to be of any task type {or task interface type};
+    they need not all be of the same [task] type.
 
-Add subclause 13.7.3:
+Modify 9.9(1):
 
-    13.7.3 The Package System.Interfaces
+    For a prefix T that is of a task type {or task interface type} (after any
+    implicit dereference), the following attributes are defined:
 
-         Static Semantics
-
-     The following language-defined library package exists:
-
-         package System.Interfaces is
-
-             type Task_Interface is limited interface;
+In the wording of AI-251:
 
-             type Protected_Interface is limited interface;
+  Add to end of 12.5.5(5) with:
 
-         end System.Interfaces;
+    The actual type shall be a task, protected, or synchronized interface
+    if and only if the formal type is also, respectively, a task, protected,
+    or synchronized interface.
 
-     Every task type has Task_Interface as an ancestor.  Every protected
-     type has Protected_Interface as an ancestor.
+  AARM Note:
 
-         Legality Rules
+      We require the kind of interface type to match exactly because without
+      that you cannot properly implement the interface.
 
-     Only a task type or another interface type may be derived from
-     Task_Interface. Only a protected type or another interface type may
-     be derived from Protected_Interface.
+[end of AI-251-relative changes]
 
+!example
 
-Modify C.7.1(2):
+    package Example is
+        type Actor is task interface;
+        procedure Give_Name(A : Actor; Name : String);
+           -- Give name to an actor
+
+        procedure Start(A : Actor);
+        procedure Stop(A : Actor);
+          -- Other operations
+
+        task type Stage_Actor is new Actor with
+          -- a task type that implements the "Actor" interface
+          -- all 3 primitives are implemented with entries
+            entry Give_Name(Name : String);
+            entry Start;
+            entry Stop;
+        end Stage_Actor;
+
+        type Private_Actor is new Actor with private;
+          -- private extension that implements Actor.
+          -- this is a "synchronized" tagged type so it
+          -- cannot be further extended (see 3.9.1(3) rule above).
 
-   {with System.Interfaces;}
-    package Ada.Task_Identification is
-        type Task_ID is private;
-        Null_Task_ID : constant Task_ID;
+    private
 
-       {function Identity(T : System.Interfaces.Task_Interface'Class)
-         return Task_ID;}
+        task type Private_Actor is new Actor with
+          -- the full type that implements the "Actor" interface"
+          -- but now Give_Name is implemented with a procedure
+            entry Start;
+            entry Stop;
+            entry Another_Entry(X : String; Y : Integer);
+        end Private_Actor;
 
-         ...
+        procedure Give_Name(PA : Private_Actor; Name : String);
 
+    end Example;
 
-!example
+  ---------------------------------------
+  -- Example with queues and worker tasks
 
-    with System.Interfaces;
     package Queues is
-        type Queue is limited interface and System.Interfaces.Protected_Interface;
-        -- Interface for a protected queue
+        type Queue is synchronized interface;
+        -- Interface for a thread-safe queue
         procedure Enqueue(Q: in out Queue; Elem : in Element_Type) is abstract;
         procedure Dequeue(Q: in out Queue; Elem : out Element_Type) is abstract;
         function Length(Q: Queue) return Natural is abstract;
@@ -309,6 +349,8 @@
 
     end Queues;
 
+    use Queues;
+
     protected type Bounded_Queue(Max: Natural) is new Queues.Queue with
       -- Implementation of a bounded, protectected queue
         entry Enqueue(Elem : in Element_Type);
@@ -321,14 +363,17 @@
         Num_Elems: Natural := 0;
     end My_Queue;
 
-    task interface Worker is
+    package Worker_Tasks is
+        type Worker is task interface;
       -- Interface for a worker task
-        entry Queue_To_Service(Q : Queue_Ref) is abstract;
-    end Server;
+        procedure Queue_To_Service(W : in out Worker; Q : Queue_Ref);
 
-    type Worker_Ref is access all Worker'Class;
+        type Worker_Ref is access all Worker'Class;
+    end Worker_Tasks;
 
-    task type Cyclic_Worker is new Worker with
+    use Worker_Tasks;
+
+    task type Cyclic_Server is new Worker_Tasks.Worker with
       -- Implementation of a cyclic worker task
         entry Queue_To_Service(Q : Queue_Ref);
     end Cyclic_Server;
@@ -351,14 +396,14 @@
             select
                 accept Add_Worker_Task(W : Worker_Ref) do
                     Num_Workers := Num_Workers + 1;
-                    Worker_Array(Num_Workers) := Worker_Ref(W);
+                    Worker_Array(Num_Workers) := W;
                 end Add_Worker_Task;
                 -- Assign new task a queue to service
                 if Num_Queues > 0 then
                     -- Assign next queue to this worker
-                    Worker_Array(Num_Workers).Assign_Queue_To_Service(
+                    Assign_Queue_To_Service(Worker_Array(Num_Workers).all,
                       Queue_Array(Next_Queue));
-                        -- Dynamically bound entry call
+                        -- Dynamically bound call, implemented by entry
 
                     -- Advance to next queue
                     Next_Queue := Next_Queue mod Num_Queues + 1;
@@ -366,7 +411,7 @@
             or
                 accept Add_Queue_To_Be_Serviced(Q : Queue_Ref);
                     Num_Queues := Num_Queues + 1;
-                    Queue_Array(Num_Queues) := Queue_Ref(Q);
+                    Queue_Array(Num_Queues) := Q;
                 end Add_Queue_To_Be_Serviced;
 
                 -- Assign queue to worker if enough workers
@@ -377,9 +422,9 @@
                   begin
                     while Offset < Num_Workers loop
                         -- (re) assign queue to worker
-                        Worker_Array((Next_Worker + Offset - Num_Queues)
-                          mod Num_Workers + 1).
-                            Assign_Queue_To_Service(Queue_Array(Num_Queues));
+                        Assign_Queue_To_Service(Worker_Array((Next_Worker + Offset - Num_Queues)
+                          mod Num_Workers + 1).all,
+                            Queue_Array(Num_Queues));
                               -- Dynamically bound entry call
 
                         Offset := Offset + Num_Queues;
@@ -402,6 +447,7 @@
     Worker_Manager.Add_Queue_To_Be_Serviced(My_Queue'Access);
     ...
 
+
 !discussion
 
 During the Ada 95 design process, it was recognized that type extension
@@ -442,14 +488,14 @@
 The next step was simply to drop the special syntax for task and
 protected interfaces completely, and define a way for entries and
 protected subprograms to effectively "override" (or at least implicitly
-"implement") "normal" inherited primitive subprograms.  Drawing on the
+"implement") "normal" inherited primitive subprograms. Drawing on the
 "prefix" notation proposed in AI-252, we now allow a normal primitive
 subprogram to be implemented by an entry or protected subprogram, so
 long as it conforms to the primitive subprogram's profile after dropping
 the first parameter. The first parameter must be controlling, and of
 mode [IN] OUT (or access-to-variable) if implemented by a protected
 procedure or entry, since protected procedures and entries are allowed
-to update the protected object.  Note that this requirement is not
+to update the protected object. Note that this requirement is not
 imposed on task entries, since "constant" task objects are permitted
 as the prefix object in a task entry call.
 
@@ -461,36 +507,27 @@
 associated abstract entries, we felt it was important not to lose the
 ability to use selective entry calls. Hence, we now permit within a
 selective entry call a dispatching call on a primitive of a limited
-interface type, since it might be implemented by an entry.  Having
+interface type, since it might be implemented by an entry. Having
 loosened this rule, it made sense to allow the use of entries renamed
 as procedures and formal subprograms in these contexts as well, since
 they also might be implemented by an entry.
 
 To allow an interface to require that it be implemented by a task or
-protected type, we have specified language-defined interfaces, tentatively
-named Task_Interface and Protected_Interface. All task types implicitly
-implement Task_Interface; all protected types implicitly implement
-Protected_Interface. The interfaces cannot be implemented explicitly by
+protected type, we have brought back a bit of special syntax.
+This additional syntax allows an interface to be specified as
+a "task" interface or a "protected" interface. To require that
+it be implemented by either a task or a protected type (to provide
+properly synchronized access to the data), the syntax allows an
+interface to be specifed as a "synchronized" interface.
+Such interfaces cannot be implemented explicitly by
 "normal" tagged types.
 
 QUESTIONS:
 
-Where should these interfaces be declared, and what should they
-be called?  Root_Task and Root_Protected are alternative names.
-And rather than System.Interfaces, they could be in a package
-called Ada.Tasking, perhaps.
-
-It might be useful to also provide a Synchonized_Interface (or
-Root_Synchronized?) to act as the common ancestor of Task_Interface and
-Protected_Interface, to cover the case where it doesn't matter whether a given
-interface is implemented by a task or a protected type, so long as it can
-safely be used concurrently from multiple tasks.  Perhaps Task_Safe would be a
-better name?
-
 In general, how should language-defined interfaces be named, especially
 ones like these which more represent "predicates" than real interfaces?
 In Java, such interfaces are typically named using adjectives, such
-as "Cloneable".  So perhaps "Is_Task" and "Is_Protected" and "Is_Task_Safe"?
+as "Cloneable". So perhaps "Is_Task" and "Is_Protected" and "Is_Task_Safe"?
 
 IMPLEMENTATION NOTES:
 
@@ -570,7 +607,7 @@
 the name/family index of that entry to the appropriate
 RTS routine along with the Param_Block and the
 appropriate extra selective entry information,
-such as the relative delay amount.  The status
+such as the relative delay amount. The status
 of this call would then determine the status of
 the call on _Selective_Entry_Call.
 
@@ -601,9 +638,9 @@
 So there wouldn't be too much overhead even when
 the feature was used.
 
-Entry families add a bit of additional complexity,
-but probably not so much as to justify disallowing
-implementing inherited subprograms using an entry family.
+We considered supporting entry families, but ultimately
+dropped the capability as not providing sufficient benefit
+given the added complexity of the model.
 
 --!corrigendum 03.0x.0x(0x)
 
@@ -3723,6 +3760,49 @@
 correctness of Ada programs! What I don't know is whether protected entry
 families are used as much in practice as they appear to be in theory. If
 they are, we ought to support them properly here.
+
+****************************************************************
+
+From: Pascal Leroy
+Sent: Monday, April 5, 2004  8:28 AM
+
+[Editor's note: this is a comment on version /05.]
+
+Nitpicking: I think you have an extraneous AND in 3.9.4(2).  Compare
+your syntax with that of AI 251.
+
+Otherwise it looks good.
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Monday, April 5, 2004  10:23 AM
+
+That was intentional.  The examples I wrote looked weird
+without some kind of connector between the word "interface"
+and the first interface name, especially when there was
+a qualifier like "task".  So while I was "augmenting"
+the syntax I added "and" as the connector.   For example:
+
+   type T is task interface Comparable;
+
+just looked weird if "Comparable" wasn't a task interface.
+
+   type T is task interface and Comparable;
+
+made a bit more sense, and didn't seem to imply that Comparable
+was itself a task interface.
+
+> Otherwise it looks good.
+
+That's good to hear.
+
+****************************************************************
+
+From: Pascal Leroy
+Sent: Monday, April 5, 2004  10:41 AM
+
+Makes sense.
 
 ****************************************************************
 

Questions? Ask the ACAA Technical Agent