Contents Index Previous Next
7.3.1 Private Operations
1
[For a type declared in the visible part of a
package or generic package, certain operations on the type do not become
visible until later in the package -- either in the private part or the
body.
{private operations} Such
private operations are available only inside the declarative region
of the package or generic package.]
Static Semantics
2
The predefined operators that exist for a given
type are determined by the classes to which the type belongs. For example,
an integer type has a predefined "+" operator. In most cases,
the predefined operators of a type are declared immediately after the
definition of the type; the exceptions are explained below. Inherited
subprograms are also implicitly declared immediately after the definition
of the type, except as stated below.
3/1
{
8652/0019}
For a composite type, the characteristics (see
7.3)
of the type are determined in part by the characteristics of its component types.
At the place where the composite type is declared, the only characteristics
of component types used are those characteristics visible at that place. If
later
immediately within the declarative region in which the composite type
is declaredwithin the immediate scope of the composite type additional
characteristics become visible for a component type, then any corresponding
characteristics become visible for the composite type. Any additional predefined
operators are implicitly declared at that place.
4/1
{
8652/0019}
The corresponding rule applies to a type defined by a
derived_type_definition,
if there is a place
immediately within the declarative region in which the
type is declaredwithin its immediate scope where additional characteristics
of its parent type become visible.
5/1
{
8652/0019}
{become nonlimited} {nonlimited
type (becoming nonlimited)} {limited
type (becoming nonlimited)} [For example, an
array type whose component type is limited private becomes nonlimited if the
full view of the component type is nonlimited and visible at some later place
immediately within the declarative region in which the array type is declared.within
the immediate scope of the array type. In such a case, the predefined "="
operator is implicitly declared at that place, and assignment is allowed after
that place.]
6/1
{
8652/0019}
Inherited primitive subprograms follow a different rule. For a
derived_type_definition,
each inherited primitive subprogram is implicitly declared at the earliest place,
if any,
immediately within the declarative region in whichwithin the
immediate scope of the
type_declaration
occurs, but after the
type_declaration,
where the corresponding declaration from the parent is visible. If there is
no such place, then the inherited subprogram is not declared at all. [An inherited
subprogram that is not declared at all cannot be named in a call and cannot
be overridden, but for a tagged type, it is possible to dispatch to it.]
7
For a private_extension_declaration,
each inherited subprogram is declared immediately after the private_extension_declaration
if the corresponding declaration from the ancestor is visible at that
place. Otherwise, the inherited subprogram is not declared for the private
extension, [though it might be for the full type].
7.a/1
Reason: There is no need
for the ``earliest place immediately within the declarative regionwithin
the immediate scope'' business here, because a private_extension_declaration
will be completed with a full_type_declaration,
so we can hang the necessary private implicit declarations on the full_type_declaration.
7.b
Discussion: The above rules
matter only when the component type (or parent type) is declared in the
visible part of a package, and the composite type (or derived type) is
declared within the declarative region of that package (possibly in a
nested package or a child package).
7.c
Consider:
7.d
package Parent is
type Root is tagged null record;
procedure Op1(X : Root);
7.e
type My_Int is range 1..10;
private
procedure Op2(X : Root);
7.f
type Another_Int is new My_Int;
procedure Int_Op(X : My_Int);
end Parent;
7.g
with Parent; use Parent;
package Unrelated is
type T2 is new Root with null record;
procedure Op2(X : T2);
end Unrelated;
7.h
package Parent.Child is
type T3 is new Root with null record;
-- Op1(T3) implicitly declared here.
7.i
package Nested is
type T4 is new Root with null record;
private
...
end Nested;
private
-- Op2(T3) implicitly declared here.
...
end Parent.Child;
7.j
with Unrelated; use Unrelated;
package body Parent.Child is
package body Nested is
-- Op2(T4) implicitly declared here.
end Nested;
7.k
type T5 is new T2 with null record;
end Parent.Child;
7.l
Another_Int does not inherit Int_Op,
because Int_Op does not ``exist'' at the place where Another_Int is declared.
7.m/1
Type T2 inherits Op1 and Op2 from
Root. However, the inherited Op2 is never declared, because Parent.Op2
is never visible immediately within the declarative regionwithin
the immediate scope of T2. T2 explicitly declares its own Op2, but
this is unrelated to the inherited one -- it does not override the inherited
one, and occupies a different slot in the type descriptor.
7.n
T3 inherits both Op1 and Op2.
Op1 is implicitly declared immediately after the type declaration, whereas
Op2 is declared at the beginning of the private part. Note that if Child
were a private child of Parent, then Op1 and Op2 would both be implicitly
declared immediately after the type declaration.
7.o/1
T4 is similar to T3, except that
the earliest place immediately within the declarative region containing
T4within T4's immediate scope where Root's Op2 is visible
is in the body of Nested.
7.p
If T3 or T4 were to declare a
type-conformant Op2, this would override the one inherited from Root.
This is different from the situation with T2.
7.q
T5 inherits Op1 and two Op2's
from T2. Op1 is implicitly declared immediately after the declaration
of T5, as is the Op2 that came from Unrelated.Op2. However, the Op2 that
originally came from Parent.Op2 is never implicitly declared for T5,
since T2's version of that Op2 is never visible (anywhere -- it never
got declared either).
7.r
For all of these rules, implicit
private parts and bodies are assumed as needed.
7.s
It
is possible for characteristics of a type to be revealed in more than
one place:
7.t
package P is
type Comp1 is private;
private
type Comp1 is new Boolean;
end P;
7.u
package P.Q is
package R is
type Comp2 is limited private;
type A is array(Integer range <>) of Comp2;
private
type Comp2 is new Comp1;
-- A becomes nonlimited here.
-- "="(A, A) return Boolean is implicitly declared here.
...
end R;
private
-- Now we find out what Comp1 really is, which reveals
-- more information about Comp2, but we're not within
-- the immediate scope of Comp2, so we don't do anything
-- about it yet.
end P.Q;
7.v
package body P.Q is
package body R is
-- Things like "xor"(A,A) return A are implicitly
-- declared here.
end R;
end P.Q;
7.v.1/1
{8652/0019}
We say immediately within the declarative region in order that types
do not gain operations within a nested scope. Consider:
7.v.2/1
package Outer is
package Inner is
type Inner_Type is private;
private
type Inner_Type is new Boolean;
end Inner;
type Outer_Type is array(Natural range <>) of Inner.Inner_Type;
end Outer;
7.v.3/1
package body Outer is
package body Inner is
-- At this point, we can see that Inner_Type is a Boolean type.
-- But we don't want Outer_Type to gain an "and" operator here.
end Inner;
end Outer;
8
[The Class
attribute is defined for tagged subtypes in
3.9. In
addition,] for every subtype S of an untagged private type whose full view is
tagged, the following attribute is defined:
9
- S'Class
-
Denotes the class-wide subtype
corresponding to the full view of S. This attribute is allowed only from
the beginning of the private part in which the full view is declared,
until the declaration of the full view. [After the full view, the Class
attribute of the full view can be used.]
10
8 Because a partial view
and a full view are two different views of one and the same type, outside
of the defining package the characteristics of the type are those defined
by the visible part. Within these outside program units the type is just
a private type or private extension, and any language rule that applies
only to another class of types does not apply. The fact that the full
declaration might implement a private type with a type of a particular
class (for example, as an array type) is relevant only within the declarative
region of the package itself including any child units.
11
The consequences of this actual implementation
are, however, valid everywhere. For example: any default initialization
of components takes place; the attribute Size provides the size of the
full view; finalization is still done for controlled components of the
full view; task dependence rules still apply to components that are task
objects.
12
9 Partial views provide assignment
(unless the view is limited), membership tests, selected components for
the selection of discriminants and inherited components, qualification,
and explicit conversion.
13
10 For a subtype S of a partial view,
S'Size is defined (see 13.3). For an object A of
a partial view, the attributes A'Size and A'Address are defined (see 13.3).
The Position, First_Bit, and Last_Bit attributes are also defined for discriminants
and inherited components.
Examples
14
Example of a
type with private operations:
15
package Key_Manager is
type Key is private;
Null_Key : constant Key; -- a deferred constant declaration (see 7.4)
procedure Get_Key(K : out Key);
function "<" (X, Y : Key) return Boolean;
private
type Key is new Natural;
Null_Key : constant Key := Key'First;
end Key_Manager;
16
package body Key_Manager is
Last_Key : Key := Null_Key;
procedure Get_Key(K : out Key) is
begin
Last_Key := Last_Key + 1;
K := Last_Key;
end Get_Key;
17
function "<" (X, Y : Key) return Boolean is
begin
return Natural(X) < Natural(Y);
end "<";
end Key_Manager;
18
11 Notes on the example:
Outside of the package Key_Manager, the operations available for objects
of type Key include assignment, the comparison for equality or inequality,
the procedure Get_Key and the operator "<"; they do not
include other relational operators such as ">=", or arithmetic
operators.
19
The explicitly declared operator "<"
hides the predefined operator "<" implicitly declared by
the full_type_declaration. Within
the body of the function, an explicit conversion of X and Y to the subtype
Natural is necessary to invoke the "<" operator of the parent
type. Alternatively, the result of the function could be written as not
(X >= Y), since the operator ">=" is not redefined.
20
The value of the variable Last_Key, declared
in the package body, remains unchanged between calls of the procedure Get_Key.
(See also the NOTES of 7.2.)
Wording Changes from Ada 83
20.a
The phrase in RM83-7.4.2(7), ``...after
the full type declaration'', doesn't work in the presence of child units,
so we define that rule in terms of visibility.
20.b
The definition of the Constrained
attribute for private types has been moved to ``Obsolescent Features.''
(The Constrained attribute of an object has not been moved there.)
Contents Index Previous Next Legal