3.9.4 Interface Types
An interface type is an abstract tagged type that
provides a restricted form of multiple inheritance. A tagged type, task
type, or protected type may have one or more interface types as ancestors.
Syntax
interface_type_definition ::=
[
limited |
task |
protected |
synchronized]
interface [
and interface_list]
Static Semantics
An interface type (also called an
interface)
is
a specific abstract tagged
type that is defined by an
interface_type_definition.
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
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 whose declaration includes the reserved
word
synchronized.
A task interface is an abstract task type. A protected
interface is an abstract protected type.
An interface type has no components.
An
interface_subtype_mark
in an
interface_list
names a
progenitor subtype; its type is the
progenitor type.
An interface type inherits user-defined primitive subprograms from each
progenitor type in the same way that a derived type inherits user-defined
primitive subprograms from its progenitor types (see
3.4).
Legality Rules
All user-defined primitive subprograms of an interface
type shall be abstract subprograms or null procedures.
The type of a subtype named in an
interface_list
shall be an interface type.
A type derived from a nonlimited interface shall
be nonlimited.
An interface derived from a task interface shall
include the reserved word
task in its definition; any other type
derived from a task interface shall be a private extension or a task
type declared by a task declaration (see
9.1).
An interface derived from a protected interface shall
include the reserved word
protected in its definition; any other
type derived from a protected interface shall be a private extension
or a protected type declared by a protected declaration (see
9.4).
An interface derived from a synchronized interface
shall include one of the reserved words task, protected,
or synchronized in its definition; any other type derived from
a synchronized interface shall be a private extension, a task type declared
by a task declaration, or a protected type declared by a protected declaration.
No type shall be derived from both a task interface
and a protected interface.
In addition to the places where Legality Rules normally
apply (see
12.3), these rules apply also in
the private part of an instance of a generic unit.
Dynamic Semantics
NOTE Nonlimited interface types have
predefined nonabstract equality operators. These can be overridden with
user-defined abstract equality operators. Such operators will then require
an explicit overriding for any nonabstract descendant of the interface.
Examples
Example of a limited
interface and a synchronized interface extending it:
type Queue
is limited interface;
procedure Append(Q :
in out Queue; Person :
in Person_Name)
is abstract;
procedure Remove_First(Q :
in out Queue;
Person :
out Person_Name)
is abstract;
function Cur_Count(Q :
in Queue)
return Natural
is abstract;
function Max_Count(Q :
in Queue)
return Natural
is abstract;
--
See 3.10.1 for Person_Name.
Queue_Error : exception;
-- Append raises Queue_Error if Cur_Count(Q) = Max_Count(Q)
-- Remove_First raises Queue_Error if Cur_Count(Q) = 0
type Synchronized_Queue
is
synchronized interface and Queue; --
see 9.11
procedure Append_Wait(Q :
in out Synchronized_Queue;
Person :
in Person_Name)
is abstract;
procedure Remove_First_Wait(Q :
in out Synchronized_Queue;
Person :
out Person_Name)
is abstract;
...
procedure Transfer(From : in out Queue'Class;
To : in out Queue'Class;
Number : in Natural := 1) is
Person : Person_Name;
begin
for I in 1..Number loop
Remove_First(From, Person);
Append(To, Person);
end loop;
end Transfer;
This defines a Queue interface defining a queue of
people. (A similar design is possible to define any kind of queue simply
by replacing Person_Name by an appropriate type.) The Queue interface
has four dispatching operations, Append, Remove_First, Cur_Count, and
Max_Count. The body of a class-wide operation, Transfer is also shown.
Every nonabstract extension of Queue will provide implementations for
at least its four dispatching operations, as they are abstract. Any object
of a type derived from Queue can be passed to Transfer as either the
From or the To operand. The two operands can be of different types in
a given call.
The Synchronized_Queue interface inherits the four
dispatching operations from Queue and adds two additional dispatching
operations, which wait if necessary rather than raising the Queue_Error
exception. This synchronized interface can only be implemented by a task
or protected type, and as such ensures safe concurrent access.
Example use of the
interface:
type Fast_Food_Queue is new Queue with record ...;
procedure Append(Q : in out Fast_Food_Queue; Person : in Person_Name);
procedure Remove_First(Q : in out Fast_Food_Queue;
Person : out Person_Name);
function Cur_Count(Q : in Fast_Food_Queue) return Natural;
function Max_Count(Q : in Fast_Food_Queue) return Natural;
...
Cashier, Counter : Fast_Food_Queue;
...
--
Add Casey (see 3.10.1) to the cashier's queue:
Append (Cashier, Casey);
--
After payment, move Casey to the sandwich counter queue:
Transfer (Cashier, Counter);
...
An interface such as Queue can be used directly as
the parent of a new type (as shown here), or can be used as a progenitor
when a type is derived. In either case, the primitive operations of the
interface are inherited. For Queue, the implementation of the four inherited
routines will necessarily be provided. Inside the call of Transfer, calls
will dispatch to the implementations of Append and Remove_First for type
Fast_Food_Queue.
Example of a task
interface:
type Serial_Device
is task interface; --
see 9.1
procedure Read (Dev :
in Serial_Device; C :
out Character)
is abstract;
procedure Write(Dev :
in Serial_Device; C :
in Character)
is abstract;
The Serial_Device interface has two dispatching operations
which are intended to be implemented by task entries (see 9.1).
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe