7.3 Private Types and Private Extensions
The declaration (in the visible part of a package)
of a type as a private type or private extension serves to separate the
characteristics that can be used directly by outside program units (that
is, the logical properties) from other characteristics whose direct use
is confined to the package (the details of the definition of the type
itself). See
3.9.1 for an overview of type
extensions.
Syntax
Legality Rules
A type shall be completely defined before it is frozen
(see
3.11.1 and
13.14).
Thus, neither the declaration of a variable of a partial view of a type,
nor the creation by an
allocator
of an object of the partial view are allowed before the full declaration
of the type. Similarly, before the full declaration, the name of the
partial view cannot be used in a
generic_instantiation
or in a representation item.
A private type is limited if its declaration includes
the reserved word limited; a private extension is limited if its
ancestor type is a limited type that is not an interface type, or if
the reserved word limited or synchronized appears in its
definition. If the partial view is nonlimited, then the full view shall
be nonlimited. If a tagged partial view is limited, then the full view
shall be limited. On the other hand, if an untagged partial view is limited,
the full view may be limited or nonlimited.
If the partial view is tagged, then the full view
shall be tagged. On the other hand, if the partial view is untagged,
then the full view may be tagged or untagged. In the case where the partial
view is untagged and the full view is tagged, no derivatives of the partial
view are allowed within the immediate scope of the partial view; derivatives
of the full view are allowed.
If a full type has
a partial view that is tagged, then:
the partial view shall be a synchronized tagged
type (see
3.9.4) if and only if the full
type is a synchronized tagged type;
the partial view shall be a descendant of an interface
type (see 3.9.4) if and only if the full type is a descendant of the
interface type.
The
ancestor subtype of
a
private_extension_declaration
is the subtype defined by the
ancestor_subtype_indication;
the ancestor type shall be a specific tagged type. The full view of a
private extension shall be derived (directly or indirectly) from the
ancestor type. In addition to the places where Legality Rules normally
apply (see
12.3), the requirement that the
ancestor be specific applies also in the private part of an instance
of a generic unit.
If a private extension inherits known discriminants
from the ancestor subtype, then the full view shall also inherit its
discriminants from the ancestor subtype, and the parent subtype of the
full view shall be constrained if and only if the ancestor subtype is
constrained.
If a partial view has unknown discriminants, then
the
full_type_declaration
may define a definite or an indefinite subtype, with or without discriminants.
If a partial view has neither known nor unknown discriminants,
then the
full_type_declaration
shall define a definite subtype.
If the ancestor subtype of a private extension has
constrained discriminants, then the parent subtype of the full view shall
impose a statically matching constraint on those discriminants.
Static Semantics
A declaration of a partial view and the corresponding
full_type_declaration
define two views of a single type. The declaration of a partial view
together with the visible part define the operations that are available
to outside program units; the declaration of the full view together with
the private part define other operations whose direct use is possible
only within the declarative region of the package itself. Moreover, within
the scope of the declaration of the full view, the characteristics (see
3.4) of the type are determined by the full
view; in particular, within its scope, the full view determines the classes
that include the type, which components, entries, and protected subprograms
are visible, what attributes and other predefined operations are allowed,
and whether the first subtype is static. See
7.3.1.
For a private extension, the characteristics (including
components, but excluding discriminants if there is a new
discriminant_part
specified), predefined operators, and inherited user-defined primitive
subprograms are determined by its ancestor type and its progenitor types
(if any), in the same way that those of a record extension are determined
by those of its parent type and its progenitor types (see
3.4
and
7.3.1).
Dynamic Semantics
NOTE 1 The partial view of a type
as declared by a
private_type_declaration
is defined to be a composite view (in
3.2).
The full view of the type can be elementary or composite. A private extension
is also composite, as is its full view.
NOTE 2 Declaring a private type with
an
unknown_discriminant_part
is a way of preventing clients from creating uninitialized objects of
the type; they are then forced to initialize each object by calling some
operation declared in the visible part of the package.
NOTE 3 The ancestor type specified
in a
private_extension_declaration
and the parent type specified in the corresponding declaration of a record
extension given in the private part can be different. If the ancestor
type is not an interface type, the parent type of the full view can be
any descendant of the ancestor type. In this case, for a primitive subprogram
that is inherited from the ancestor type and not overridden, the formal
parameter names and default expressions (if any) come from the corresponding
primitive subprogram of the specified ancestor type, while the body comes
from the corresponding primitive subprogram of the parent type of the
full view. See
3.9.2.
NOTE 4 If the ancestor type specified
in a
private_extension_declaration
is an interface type, the parent type can be any type so long as the
full view is a descendant of the ancestor type. The progenitor types
specified in a
private_extension_declaration
and the progenitor types specified in the corresponding declaration of
a record extension given in the private part are not necessarily the
same — it is only necessary that the private extension and the
record extension be descended from the same set of interfaces.
Examples
Examples of private
type declarations:
type Key is private;
type File_Name is limited private;
Example of a private
extension declaration:
type List is new Ada.Finalization.Controlled with private;
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe