12.6 Formal Subprograms
subprograms can be used to pass callable entities to a generic unit.]
Language Design Principles
Reason: There are
no null functions because the return value has to be constructed somehow.
We don't allow null for abstract formal procedures, as the operation
is dispatching. It doesn't seem appropriate (or useful) to say that the
implementation of something is null in the formal type and all possible
descendants of that type. This also would define a dispatching operation
that doesn't correspond to a slot in the tag of the controlling type,
which would be a new concept. Finally, additional rules would be needed
to define the meaning of a dispatching null procedure (for instance,
the convention of such a subprogram should be intrinsic, but that's not
what the language says). It doesn't seem worth the effort.
Name Resolution Rules
The expected profile for the
if any, is that of the formal subprogram.
This rule, unlike others
in this clause, is observed at compile time of the generic_declaration
For a generic formal subprogram,
the expected profile for the actual is that of the formal subprogram.
The profiles of the formal and any named default shall be mode
This rule, unlike others
in this clause, is checked at compile time of the generic_declaration
The profiles of the formal and actual shall be mode
if the actual matching the
denotes a generic formal object of another generic unit G, and
the instantiation containing the actual that occurs within the body of
a generic unit G or within the body of a generic unit declared
within the declarative region of the generic unit G, then the
corresponding parameter or result type of the formal subprogram of G
shall have a null_exclusion;
otherwise, the subtype of
the corresponding parameter or result type of the actual matching the
shall exclude null. In addition to the places where
Legality Rules normally apply (see 12.3),
this rule applies also in the private part of an instance of a generic
This rule prevents “lying”. Null must never be
the value of a parameter or result with an explicit null_exclusion.
The first bullet is an assume-the-worst rule which prevents trouble in
generic bodies (including bodies of child generics) when the formal subtype
excludes null implicitly.
specific tagged type could be any of a formal tagged private type, a
formal derived type, a formal interface type, or a normal tagged type.
While the last case doesn't seem to be very useful, there isn't any good
reason for disallowing it. This rule ensures that the operation is a
dispatching operation of some type, and that we unambiguously know what
that type is.
We informally call a subprogram
declared by a formal_abstract_subprogram_declaration
an abstract formal subprogram, but we do not use this term in
normative wording. (We do use it often in these notes.)
This means that the actual is either a primitive operation of the
controlling type, or an abstract formal subprogram. Also note that this
prevents the controlling type from being class-wide (with one exception
explained below), as only specific types have primitive operations (and
a formal subprogram eventually has to have an actual that is a primitive
of some type). This could happen in a case like:
type T(<>) is tagged private;
with procedure Foo (Obj : in T) is abstract;
package P ...
package New_P is new P (Something'Class, Some_Proc);
The instantiation here
is always illegal, because Some_Proc could never be a primitive operation
of Something'Class (there are no such operations). That's good, because
we want calls to Foo always to be dispatching calls.
it is possible for a formal tagged type to be instantiated with a class-wide
type, it is possible for the (real) controlling type to be class-wide
in one unusual case:
type NT(<>) is new T with private;
-- Presume that T has the following primitive operation:
-- with procedure Bar (Obj : in T);
package Gr ...
package body Gr is
package New_P2 is new P (NT, Foo => Bar);
package New_Gr is new Gr (Something'Class);
The instantiation of New_P2
is legal, since Bar is a dispatching operation of the actual type of
the controlling type of the abstract formal subprogram Foo. This is not
a problem, since the rules given in 12.5.1
explain how this routine dispatches even though its parameter is class-wide.
Note that this legality
rule never needs to be rechecked in an instance (that contains a nested
instantiation). The rule only talks about the actual type of the instantiation;
it does not require looking further; if the actual type is in fact a
formal type, we do not intend looking at the actual for that formal.
declares a generic formal subprogram. The types of the formal parameters
and result, if any, of the formal subprogram are those determined by
given in the formal_subprogram_declaration
however, independent of the particular subtypes that are denoted by the
the nominal subtypes of the formal parameters and result, if any, are
defined to be nonstatic, and unconstrained if of an array type [(no applicable
index constraint is provided in a call on a formal subprogram)]. In an
instance, a formal_subprogram_declaration
declares a view of the actual. The profile of this view takes its subtypes
and calling convention from the original profile of the actual entity,
while taking the formal parameter name
from the profile given in the formal_subprogram_declaration
The view is a function or procedure, never an entry.
This rule is intended to
be the same as the one for renamings-as-declarations, where the formal_subprogram_declaration
is analogous to a renaming-as-declaration, and the actual is analogous
to the renamed view.
If a subtype_mark
in the profile of the formal_subprogram_declaration
denotes a formal private or formal derived type and the actual type for
this formal type is a class-wide type T'Class, then for the purposes
of resolving the corresponding actual subprogram at the point of the
instantiation, certain implicit declarations may be available as possible
resolutions as follows:
For each primitive subprogram
of T that is directly visible at the point of the instantiation,
and that has at least one controlling formal parameter, a corresponding
implicitly declared subprogram with the same defining name, and having
the same profile as the primitive subprogram except that T is
systematically replaced by T'Class in the types of its profile,
is potentially use-visible. The body of such a subprogram is as defined
in 12.5.1 for primitive subprograms of a
formal type when the actual type is class-wide.
This gives the same capabilities to formal subprograms
as those that primitive operations of the formal type have when the actual
type is class-wide. We do not want to discourage the use of explicit
declarations for (formal) subprograms!
Although the above wording seems to require constructing
implicit versions of all of the primitive subprograms of type T,
it should be clear that a compiler only needs to consider those that
could possibly resolve to the corresponding actual subprogram. For instance,
if the formal subprogram is a procedure with two parameters, and the
actual subprogram name is Bar (either given explicitly or by default),
the compiler need not consider primitives that are functions, that have
the wrong number of parameters, that have defining names other than Bar,
and so on; thus it does not need to construct implicit declarations for
Functions that only have a controlling result and
do not have a controlling parameter of T are not covered by this
rule, as any call would be required to raise Program_Error by 12.5.1.
It is better to detect the error earlier than at runtime.
If a generic unit has a subprogram_default
specified by a box, and the corresponding actual parameter is omitted,
then it is equivalent to an explicit actual parameter that is a usage
name identical to the defining name of the formal.
Reason: This is
necessary to trigger all of the dispatching operation rules. It otherwise
would not be considered a dispatching operation, as formal subprograms
are never primitive operations.
13 The matching rules for formal subprograms
state requirements that are similar to those applying to subprogram_renaming_declaration
). In particular, the name of a
parameter of the formal subprogram need not be the same as that of the
corresponding parameter of the actual subprogram; similarly, for these
need not correspond.
14 The constraints that apply to a parameter
of a formal subprogram are those of the corresponding formal parameter
of the matching actual subprogram (not those implied by the corresponding
in the _specification
of the formal subprogram).
A similar remark applies to the result of a function. Therefore, to avoid
confusion, it is recommended that the name
of a first subtype be used in any declaration of a formal subprogram.
15 The subtype specified for a formal parameter
of a generic formal subprogram can be any visible subtype, including
a generic formal subtype of the same generic_formal_part
16 A formal subprogram is matched by an
attribute of a type if the attribute is a function with a matching specification.
An enumeration literal of a given type matches a parameterless formal
function whose result type is the given type.
17 A default_name
denotes an entity that is visible or directly visible at the place of
a box used as a default is equivalent to a name that denotes an entity
that is directly visible at the place of the _instantiation
Proof: Visibility and name resolution
are applied to the equivalent explicit actual parameter.
A null procedure as a subprogram default has convention
Intrinsic (see 6.3.1).
Proof: This is
an implicitly declared subprogram, so it has convention Intrinsic as
defined in 6.3.1.
Examples of generic
"+"(X, Y : Item) return
Image(X : Enum) return
with procedure Pre_Action(X : in Item) is null; -- defaults to no action
with procedure Write(S : not null access Root_Stream_Type'Class;
Desc : Descriptor)
is abstract Descriptor'Write; -- see 13.13.2
-- Dispatching operation on Descriptor with default
-- given the generic procedure declaration
with procedure Action (X : in Item);
procedure Iterate(Seq : in Item_Sequence);
-- and the procedure
procedure Put_Item(X : in Item);
-- the following instantiation is possible
procedure Put_List is new Iterate(Action => Put_Item);
Extensions to Ada 95
The formal subprogram default of null is
new. It allows the default of a generic procedure to do nothing, such
as for passing a debugging routine.
Wording Changes from Ada 95
Extensions to Ada 2005
Correction: Added construction
of implicit subprograms for primitives of class-wide actual types, to
make it possible to import subprograms via formal subprograms as well
as by implicit primitive operations of a formal type. (This is a Correction
as it is very important for the usability of indefinite containers when
instantiated with class-wide types; thus we want Ada 2005 implementations
to support it.)
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe