12.6 Formal Subprograms
[
Formal
subprograms can be used to pass callable entities to a generic unit.]
Language Design Principles
Syntax
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
default_name,
if any, is that of the formal subprogram.
For a generic formal subprogram,
the expected profile for the actual is that of the formal subprogram.
Legality Rules
{
AI05-0239-1}
The profiles of the formal and any named default shall be mode conformant.
{
AI05-0239-1}
The profiles of the formal and actual shall be mode conformant.
{
AI12-0183-1}
{
AI12-0287-1}
if the actual matching the
formal_subprogram_declaration
statically denotes a generic formal subprogram of another generic unit
G, and the instantiation containing the actual 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
formal_subprogram_declaration
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
unit.
Reason: 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.
{
AI12-0204-1}
If the named default, if any, is a prefixed view, the prefix of that
view shall denote an object for which renaming is allowed (see
8.5.1).
Similarly, if the actual subprogram in an instantiation is a prefixed
view, the prefix of that view shall denote an object for which renaming
is allowed.
Reason: {
AI12-0204-1}
The prefix in such a case is essentially renamed at the point of the
instantiation and passed to any calls of the formal subprogram in the
generic. If the prefix isn't legal to rename, that doesn't make sense
(and allowing it might end up passing a nonexistent object to some calls).
Ramification: The 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.)
a dispatching operation of the controlling type;
or
if the controlling type is a formal type, and the
actual type corresponding to that formal type is a specific type T,
a dispatching operation of type T; or
if the controlling type is a formal type, and the
actual type is a class-wide type T'Class, an implicitly declared
subprogram corresponding to a primitive operation of type T (see
Static Semantics below).
Ramification: {
AI12-0165-1}
This means that the actual is a primitive operation of the controlling
type, an abstract formal subprogram, or the implicitly available primitive
operation for a class-wide type.
{
AI12-0165-1}
{
AI12-0005-1}
An explicit class-wide operation cannot be used for the actual of a formal
abstract subprogram. Such an operation is never primitive (only specific
types have primitive subprograms).
generic
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);
{
AI12-0165-1}
If Some_Proc is an explicit class-wide operation, the instantiation here
is illegal, because Some_Proc is not a primitive operation of Something'Class
(there are no such operations).
{
AI12-0165-1}
However, if Some_Proc is a primitive operation of type Something, then
the instantiation is legal; the actual is the implicitly generated subprogram
described in Static Semantics below. 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.
{
AI12-0165-1}
We allow this special case because it is possible for a class-wide operation
to be primitive inside of an instance, and the contract model does not
allow us to make such cases illegal. As such, it seems inconsistent to
not allow the same in explicit instantiations.
{
AI12-0005-1}
{
AI12-0165-1}
Specifically, since 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 as in the following unusual case:
{
AI12-0005-1}
generic
type NT(<>)
is new T
with private;
--
Presume that T has the following primitive operation:
--
procedure Bar (Obj :
in T);
package Gr ...
package body Gr is
package New_P2 is new P (NT, Foo => Bar);
end Gr;
package New_Gr is new Gr (Something'Class);
{
AI12-0165-1}
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. Again, the rules given in
12.5.1 explain
how this routine dispatches.
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.
Static Semantics
A
formal_subprogram_declaration
declares a generic formal subprogram. The types of the formal parameters
and result, if any, of the formal subprogram are those determined by
the
subtype_marks
given in the
formal_subprogram_declaration;
however, independent of the particular subtypes that are denoted by the
subtype_marks,
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
names
and
default_expressions
from the profile given in the
formal_subprogram_declaration.
The view is a function or procedure, never an entry.
Discussion: 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.
{
AI05-0071-1}
{
AI05-0131-1}
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.
Reason: {
AI05-0071-1}
{
AI05-0131-1}
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!
Implementation Note: {
AI05-0071-1}
{
AI05-0131-1}
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 those primitives.
Ramification: {
AI05-0071-1}
{
AI05-0131-1}
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 run time.
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.
NOTE 1 {
AI12-0442-1}
The matching rules for formal subprograms state requirements that are
similar to those applying to
subprogram_renaming_declarations
(see
8.5.4). In particular, the name of a
parameter of the formal subprogram can be different from that of the
corresponding parameter of the actual subprogram; similarly, for these
parameters,
default_expressions
can be different.
NOTE 2 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
subtype_mark
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.
NOTE 3 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.
NOTE 4 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.
Proof: Visibility and name resolution
are applied to the equivalent explicit actual parameter.
NOTE 8 {
AI95-00348-01}
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
Examples of generic
formal subprograms:
{
AI95-00433-01}
with function "+"(X, Y : Item)
return Item
is <>;
with function Image(X : Enum)
return String
is Enum'Image;
with procedure Update
is Default_Update;
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
generic
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
{
AI95-00348-01}
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
Incompatibilities With Ada 2005
{
AI05-0296-1}
It is now illegal to declare a formal abstract subprogram
whose controlling type is incomplete. It was never intended to allow
that, and such a type would have to come from outside of the generic
unit in Ada 2005, so it is unlikely to be useful. Moreover, a dispatching
call on the subprogram is likely to fail in many implementations. So
it is very unlikely that any code will need to be changed because of
this new rule.
Extensions to Ada 2005
{
AI05-0071-1}
{
AI05-0131-1}
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.)
Incompatibilities With Ada 2012
{
AI12-0204-1}
Correction: Added a rule to ensure that for
an actual subprogram that is a prefixed view, the prefix continues to
exist during the life of the instantiation. If the prefix is a subcomponent
that depends on discriminants, Ada 2005 and 2012 would have allowed the
prefix while Ada 2022 would not. Without this change, explicit forms
(renaming the object and then using that in instantiations) would be
safer than directly using the prefixed view; that's inconsistent with
other kinds of actual subprograms.
Extensions to Ada 2012
{
AI12-0165-1}
Correction: We now allow the actual for a
formal_abstract_subprogram_declaration
to be an implicitly declared subprogram for a class-wide type. The rules
already required a compiler to be able to construct this subprogram for
use in an instantiation that occurs inside of a generic unit, so it made
no sense to prevent it from being used explicitly as well (in the same
way that the previous extension allows them to be used for other kinds
of formal subprograms).
Wording Changes from Ada 2012
{
AI12-0287-1}
Correction: Added wording to ensure that the object subject to
a Legality Rule can be determined at compile-time. The alternative being
nonsense, we treat this as a wording change.
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe