CVS difference for ais/ai-00345.txt

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

--- ais/ai-00345.txt	2003/08/08 01:44:10	1.1
+++ ais/ai-00345.txt	2003/09/30 02:01:14	1.2
@@ -1,23 +1,226 @@
-!standard  3.04.03    (00)                             03-08-07  AI95-00345/00
+!standard  3.04.03    (00)                             03-09-28  AI95-00345/01
 !class amendment 03-08-07
 !status received 03-06-12
 !priority Medium
 !difficulty Hard
-!subject Protected interfaces
+!subject Protected and task interfaces
 
 !summary
 
+Protected and Task interfaces are proposed. A protected or task
+type may specify one or more interfaces as ancestors. The synchronizing
+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.
+
 !problem
 
+The object-oriented features of Ada 95 are essentially disjoint with
+the multi-tasking features of Ada 95. This means that it is difficult
+to combine synchronization with type extension and polymorphism.
+Although there are some approaches to doing so using access discriminants,
+they tend to be a bit awkward, and they don't actually prevent unsynchronized
+access to the object designated by the access discriminant.
+
 !proposal
 
+Augment the syntax for tasks and protected type declarations
+to allow task and protected interfaces, as follows:
+
+  task_interface_declaration ::=
+    TASK INTERFACE defining_identifier IS
+      [NEW task_interface_name {AND task_interface_name} WITH] task_interface_definition;
+
+  task_interface_definition ::= {abstract_entry_declaration} END [task_identifier]
+
+  task_type_declaration ::=
+    TASK TYPE defining_identifier [known_discriminant_part] [IS
+      [NEW task_interface_name {AND task_interface_name} WITH] task_definition];
+
+  protected_interface_declaration ::=
+    PROTECTED INTERFACE defining_identifier IS
+      [NEW protected_interface_name {AND protected_interface_name} WITH]
+      protected_interface_definition;
+
+
+  protected_interface_definition ::= {protected_interface_item} END [protected_identifier]
+
+  protected_interface_item ::= abstract_subprogram_declaration
+    | null_procedure_declaration
+    | abstract_entry_declaration
+
+  protected_type_declaration ::=
+    PROTECTED TYPE defining_identifier [known_discriminant_part] IS
+      [NEW protected_interface_name {AND protected_interface_name} WITH] protected_definition;
+
+  protected_operation_declaration ::= subprogram_declaration
+    | null_procedure_declaration
+    | entry_declaration
+    | aspect_clause
+
+  abstract_entry_declaration ::=
+    ENTRY defining_identifier [(discrete_subtype_definition)] parameter_profile IS ABSTRACT;
+
+As with "normal" interfaces, a "concrete" type that inherits from
+an interface must override all abstract operations, but may inherit
+null procedures. We have not proposed null entries, since it is unclear
+what would be the barriers for those (True or False) or how they would
+fit into a task body (no accept statement?).
+
+Objects of type <protected/task_interface>'Class could be used as the
+prefix in a call on a synchronizing operation, and a run-time dispatch
+would occur to the "appropriate" entry/protected subprogram.
+
+Question: Should we allow declaration of operations outside the
+protected/task_interface definition that take directly a
+a protected or task interface, as opposed to the corresponding class-wide type?
+
+Suggested answer: No, do not allow operations that directly take protected
+or task interfaces.  This means we avoid the whole issue of non-synchronizing
+dispatching operations for these types, which would require something
+analogous to tagged-type dispatching tables. By limiting ourselves to
+synchronizing operations, the implementation burden for supporting
+protected and task interfaces should be minimized.
+
 !wording
 
 !example
 
+    protected interface Queue is
+      -- Interface for a protected queue
+        entry Enqueue(Elem : in Element_Type) is abstract;
+        entry Dequeue(Elem : out Element_Type) is abstract;
+        function Length return Natural is abstract;
+    end Queue;
+
+    type Queue_Ref is access all Queue'Class;
+
+    protected type Bounded_Queue(Max: Natural) is new Queue with
+      -- Implementation of a bounded, protectected queue
+        entry Enqueue(Elem : in Element_Type);
+	entry Dequeue(Elem : out Element_Type);
+        function Length return Natural;
+    private
+        Data: Elem_Array(1..Max);
+	In_Index: Positive := 1;
+        Out_Index: Positive := 1;
+        Num_Elems: Natural := 0;
+    end My_Queue;
+
+    task interface Worker is
+      -- Interface for a worker task
+	entry Queue_To_Service(Q : Queue_Ref) is abstract;
+    end Server;
+
+    type Worker_Ref is access all Worker'Class;
+
+    task type Cyclic_Worker is new Worker with
+      -- Implementation of a cyclic worker task
+	entry Queue_To_Service(Q : Queue_Ref);
+    end Cyclic_Server;
+
+    task Worker_Manager is
+      -- Task that manages servers and queues.
+	entry Add_Worker_Task(W : Worker_Ref);
+        entry Add_Queue_To_Be_Serviced(Q : Queue_Ref);
+    end Worker_Manager;
+
+    task body Worker_Manager is
+	Worker_Array : array(1..100) of Worker_Ref;
+	Queue_Array : array(1..10) of Queue_Ref;
+	Num_Workers : Natural := 0;
+	Next_Worker : Integer := Worker_Array'First;
+	Num_Queues : Natural := 0;
+	Next_Queue : Integer := Queue_Array'First;
+    begin
+	loop
+	    select
+		accept Add_Worker_Task(W : Worker_Ref) do
+		    Num_Workers := Num_Workers + 1;
+		    Worker_Array(Num_Workers) := Worker_Ref(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(
+		      Queue_Array(Next_Queue));
+			-- Dynamically bound entry call
+
+		    -- Advance to next queue
+		    Next_Queue := Next_Queue mod Num_Queues + 1;
+		end if;
+	    or
+		accept Add_Queue_To_Be_Serviced(Q : Queue_Ref);
+		    Num_Queues := Num_Queues + 1;
+		    Queue_Array(Num_Queues) := Queue_Ref(Q);
+		end Add_Queue_To_Be_Serviced;
+
+		-- Assign queue to worker if enough workers
+		if Num_Workers >= Num_Queues then
+		    -- This queue should be given one or more workers
+		  declare
+		    Offset : Natural := Num_Queues-1;
+		  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));
+			      -- Dynamically bound entry call
+
+			Offset := Offset + Num_Queues;
+		    end loop;
+
+		    -- Advance to next worker
+		    Next_Worker := Next_Worker mod Num_Workers + 1;
+		  end;
+		end if;
+	    or
+		terminate;
+	    end select;
+	end loop;
+    end Worker_Manager;
+
+    My_Queue : aliased Bounded_Queue(Max => 10);
+    My_Server : aliased Cyclic_Server;
+  begin
+    Worker_Manager.Add_Worker_Task(My_Server'Access);
+    Worker_Manager.Add_Queue_To_Be_Serviced(My_Queue'Access);
+    ...
+
+
 !discussion
+
+During the Ada 95 design process, it was recognized that type extension
+might be useful for protected types (and possibly task types) as well as
+for record types.  However, at the time, both type extension and
+protected types were somewhat controversial, and expending energy on a
+combination of these two controversial features was not practical.
+
+Since the design, however, this lack of extension of protected types has
+been identified as a possible target for future enhancements. In
+particular, a concrete proposal appeared in the May 2000 issue of ACM
+Transactions on Programming Languages in Systems (ACM TOPLAS), and this
+has formed the basis for a language amendment (AI-00250).
+
+However, in ARG discussions, the complexity of this proposal has been of
+concern, and more recently a simpler suggestion was made that rather
+than supporting any kind of implementation inheritance, interfaces for
+tasks and protected types might be defined, and then concrete
+implementations of these interfaces could be provided. Class-wide types
+for these interfaces would be defined, and calls on the operations
+(protected subprograms and entries) defined for these interfaces could
+be performed given only a class-wide reference to the task or protected
+object.
+
+An important advantage of eliminating inheritance of any code or data
+for tasks and protected types is that the "monitor"-like benefits of
+these constructs are preserved.  All of the synchronizing operations are
+implemented in a single module, simplifying analysis and avoiding any
+inheritance "anomolies" that have been associated in the literature with
+combining inheritance with synchronization.
 
-!corrigendum 03.09.01(03)
+--!corrigendum 03.0x.0x(0x)
 
 !ACATS test
 

Questions? Ask the ACAA Technical Agent