9.4 Protected Units and Protected Objects

A
protected object provides coordinated access to shared data, through
calls on its visible protected operations, which can be protected
subprograms or protected entries. A
protected unit is declared by a protected declaration,
which has a corresponding protected_body.
A protected declaration may be a protected_type_declaration,
in which case it declares a named protected type; alternatively, it may
be a single_protected_declaration,
in which case it defines an anonymous protected type, as well as declaring
a named protected object of that type.

Reason: We allow the operations and components
to be mixed because that's how other things work (for example, package
declarations). We have relaxed the ordering rules for the items inside
declarative_parts
and task_definitions
as well.

{AI95-00345-01}
{AI95-00397-01}
{AI95-00399-01}
{AI95-00419-01}
{AI05-0042-1}
For a protected declaration with an interface_list,
the protected type inherits user-defined primitive subprograms from each
progenitor type (see 3.9.4), in the same
way that a derived type inherits user-defined primitive subprograms from
its progenitor types (see 3.4). If the first
parameter of a primitive inherited subprogram is of the protected type
or an access parameter designating the protected type, and there is a
protected_operation_declaration
for a protected subprogram or single entry with the same identifier within
the protected declaration, whose profile is type conformant with the
prefixed view profile of the inherited subprogram, the inherited subprogram
is said to be implemented by the conforming protected subprogram
or entry using an implicitly declared nonabstract subprogram which has
the same profile as the inherited subprogram and which overrides it.

Reason: {AI05-0042-1}
The part about the implicitly declared subprogram is needed so that a
subprogram implemented by an entry or subprogram is considered to be
overridden for the purpose of the other rules of the language. Without
it, it would for instance be illegal for an abstract subprogram to be
implemented by an entry, because the abstract subprogram would not be
overridden. The Legality Rules below ensure that there is no conflict
between the implicit overriding subprogram and a user-defined overriding
subprogram.

Proof: 3.9.4
requires that an interface_list
only name interface types, and limits the descendants of the various
kinds of interface types. Only a limited, protected, or synchronized
interface can have a protected type descendant. Nonlimited or task interfaces
are not allowed, as they offer operations that a protected type does
not have.

{AI95-00397-01}
{AI05-0042-1}
The prefixed view profile of an explicitly declared primitive subprogram
of a tagged protected type shall not be type conformant with any protected
operation of the protected type, if the subprogram has the same defining
name as the protected operation and the first parameter of the subprogram
is of the protected type or is an access parameter designating the protected
type.

Reason: This prevents the existence of
two operations with the same name and profile which could be called with
a prefixed view. If the operation was inherited, this would be illegal
by the following rules; this rule puts inherited and noninherited routines
on the same footing. Note that this only applies to tagged protected
types (that is, those with an interface in their declaration); we do
that as there is no problem with prefixed view calls of primitive operations
for “normal” protected types, and having this rule apply
to all protected types would be incompatible with Ada 95.

{AI95-00345-01}
the inherited subprogram is overridden with a primitive subprogram of
the protected type, in which case the overriding subprogram shall be
subtype conformant with the inherited subprogram and not abstract; or

{AI95-00345-01}
{AI95-00397-01}
the inherited subprogram is implemented by a protected subprogram or
single entry of the protected type, in which case its prefixed view profile
shall be subtype conformant with that of the protected subprogram or
entry.

If neither applies, the inherited subprogram shall
be a null procedure. In addition to the places where
Legality Rules normally apply (see 12.3),
these rules also apply in the private part of an instance of a generic
unit.

Reason: Each inherited subprogram can
only have a single implementation (either from overriding a subprogram,
implementing a subprogram, or implementing an entry), and must have an
implementation unless the subprogram is a null procedure.

{AI95-00345-01}
{AI05-0291-1}
If an inherited subprogram is implemented by a protected procedure or
an entry, then the first parameter of the inherited subprogram shall
be of mode out or in out, or an access-to-variable parameter.
If an inherited subprogram is implemented by a protected function, then
the first parameter of the inherited subprogram shall be of mode in,
but not an access-to-variable parameter.

Reason: For a protected procedure or
entry, the protected object can be read or written (see 9.5.1).
A subprogram that is implemented by a protected procedure or entry must
have a profile which reflects that in order to avoid confusion. Similarly,
a protected function has a parameter that is a constant, and the inherited
routine should reflect that.

Discussion: These rules are subtly different
than those for subprograms (see 8.3.1) because
there cannot be “late” inheritance of primitives from interfaces.
Hidden (that is, private) interfaces are prohibited explicitly (see 7.3),
as are hidden primitive operations (as private operations of public abstract
types are prohibited — see 3.9.3).

[The execution resource associated with a protected
object has to be acquired to read or update any components of the protected
object; it can be acquired (as part of a protected action — see
9.5.1) either for concurrent read-only access,
or for exclusive read-write access.]

As the first
step of the finalization of a protected object, each call remaining
on any entry queue of the object is removed from its queue and Program_Error
is raised at the place of the corresponding entry_call_statement.

Reason: This
is analogous to the raising of Tasking_Error in callers of a task that
completes before accepting the calls. This situation can only occur due
to a requeue (ignoring premature unchecked_deallocation), since any task
that has accessibility to a protected object is awaited before finalizing
the protected object. For example:

Bounded (Run-Time) Errors

{AI95-00280-01}
It is a bounded error to call an entry or subprogram
of a protected object after that object is finalized. If the error is
detected, Program_Error is raised. Otherwise, the call proceeds normally,
which may leave a task queued forever.

Reason: This is very similar to the finalization
rule. It is a bounded error so that an implementation can avoid the overhead
of the check if it can ensure that the call still will operate properly.
Such an implementation cannot need to return resources (such as locks)
to an executive that it needs to execute calls.

with Ada.Finalization.Controlled;package Window_Manager is
...type Root_Window is new Ada.Finalization.Controlled with private;type Any_Window is access all Root_Window;
...private
...procedure Finalize (Object : in out Root_Window);
...end Window_Manager;

The environment task will call Window_Lock for
the object allocated for A_Window when the collection for Any_Window
is finalized, which will happen after the finalization of Window_Lock
(because finalization of the package body will occur before that of the
package specification).

13 {AI95-00382-01}
Within the declaration or body of a protected unit other than in an access_definition,
the name of the protected unit denotes the current instance of the unit
(see 8.6), rather than the first subtype of
the corresponding protected type (and thus the name cannot be used as
a subtype_mark).

14 A selected_component
can be used to denote a discriminant of a protected object (see 4.1.3).
Within a protected unit, the name of a discriminant of the protected
type denotes the corresponding discriminant of the current instance of
the unit.

Reason: Component_declarations
are disallowed in a protected_body
because, for efficiency, we wish to allow the compiler to determine the
size of protected objects (when not dynamic); the compiler cannot necessarily
see the body. Furthermore, the semantics of initialization of such objects
would be problematic — we do not wish to give protected objects
complex initialization semantics similar to task activation.

Incompatibilities With Ada 2005

{AI05-0291-1}
Correction: When an inherited subprogram is
implemented by a protected function, the first parameter has to be an
in parameter, but not an access-to-variable type. Original Ada
2005 allowed access-to-variable parameters in this case; the parameter
will need to be changed to access-to-constant with the addition of the
constant keyword.

Extensions to Ada 2012

{AI12-0147-1}
Corrigendum: Null procedures
and expression functions are allowed in protected bodies. We consider
this an omission, as there is no reason why the convinient shorthand
notations should not be allowed in this context.