3.9.4 Interface Types

{AI95-00251-01}
{AI95-00345-01}
[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.]

Glossary entry: An interface type is
a form of abstract tagged type which has no components or concrete operations
except possibly null procedures. Interface types are used for composing
other interfaces and tagged types and thereby provide multiple inheritance.
Only an interface type can be used as a progenitor of another type.

Language Design Principles

{AI95-00251-01}
{AI95-00345-01}
The rules are designed so that an interface can be used as either a parent
type or a progenitor type without changing the meaning. That's important
so that the order that interfaces are specified in a derived_type_definition
is not significant. In particular, we want:

Static Semantics

{AI95-00345-01}
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.

Glossary entry: A synchronized entity
is one that will work safely with multiple tasks at one time. A synchronized
interface can be an ancestor of a task or a protected type. Such a task
or protected type is called a synchronized tagged type.

{AI95-00345-01}
{AI95-00443-01}
[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.

Ramification: The class-wide type associated
with a tagged task type (including a task interface type) is a task type,
because “task” is one of the language-defined classes of
types (see 3.2). However, the class-wide type
associated with an interface is not an interface type, as “interface”
is not one of the language-defined classes (as it is not closed
under derivation). In this sense, “interface” is similar
to “abstract”. The class-wide type associated with an interface
is a concrete (nonabstract) indefinite tagged composite type.

Reason: This ensures that task operations
(like abort and the Terminated attribute) can be applied to a task interface
type and the associated class-wide type. While there are no protected
type operations, we apply the same rule to protected interfaces for consistency.

{AI95-00419-01}
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).

Glossary entry: A progenitor of a derived
type is one of the types given in the definition of the derived type
other than the first. A progenitor is always an interface type. Interfaces,
tasks, and protected types may also have progenitors.

{AI95-00345-01}
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).

{AI95-00345-01}
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).

{AI95-00345-01}
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.

Reason: We require that an interface
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).

Reason: This prevents a single private
extension from inheriting from both a task and a protected interface.
For a private type, there can be no legal completion. For a generic formal
derived type, there can be no possible matching type (so no instantiation
could be legal). This rule provides early detection of the errors.

Ramification: {AI05-0299-1}
This paragraph is intended to apply to all of the Legality Rules in this
subclause. We cannot allow interface types which do not obey these rules,
anywhere. Luckily, deriving from a formal type (which might be an interface)
is not allowed for any tagged types in a generic body. So checking in
the private part of a generic covers all of the cases.

85 {AI95-00411-01}
Nonlimited interface types have predefined nonabstract equality operators.
These may be overridden with user-defined abstract equality operators.
Such operators will then require an explicit overriding for any nonabstract
descendant of the interface.

type Synchronized_Queue is synchronized interface and Queue; -- see 9.11procedure 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;beginfor 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 could be created 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 must provide implementations for
at least its four dispatching operations, as they are abstract. Any object
of a type derived from Queue may be passed to Transfer as either the
From or the To operand. The two operands need not be of the same type
in any 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 may only be implemented by a task
or protected type, and as such ensures safe concurrent access.

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 must be provided. Inside the call of Transfer, calls will dispatch
to the implementations of Append and Remove_First for type Fast_Food_Queue.