7.4. Private Type and Deferred Constant Declarations

[PREVIOUS][UP][NEXT]

The declaration of a type as a private type in the visible part of a package 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). Deferred constant declarations declare constants of private types.

    private_type_declaration ::=
       type identifier [discriminant_part] is [limited] private; 

    deferred_constant_declaration ::=
       identifier_list : constant type_mark; 

A private type declaration is only allowed as a declarative item of the visible part of a package, or as the generic parameter declaration for a generic formal type in a generic formal part.

The type mark of a deferred constant declaration must denote a private type or a subtype of a private type; a deferred constant declaration and the declaration of the corresponding private type must both be declarative items of the visible part of the same package. A deferred constant declaration with several identifiers is equivalent to a sequence of single deferred constant declarations as explained in section 3.2.

Examples of private type declarations:

    type KEY is private;
    type FILE_NAME is limited private; 

Example of deferred constant declaration:

    NULL_KEY : constant KEY;  

References: constant, declaration, declarative item, deferred constant, discriminant part, generic formal part, generic formal type, generic parameter declaration, identifier, identifier list, limited type, package, private type, program unit, subtype, type, type mark, visible part.

Sub-topics:

7.4.1. Private Types

[UP][NEXT]

If a private type declaration is given in the visible part of a package, then a corresponding declaration of a type with the same identifier must appear as a declarative item of the private part of the package. The corresponding declaration must be either a full type declaration or the declaration of a task type. In the rest of this section explanations are given in terms of full type declarations; the same rules apply also to declarations of task types.

A private type declaration and the corresponding full type declaration define a single type. The private type declaration, together with the visible part, define the operations that are available to outside program units (see section 7.4.2 on the operations that are available for private types). On the other hand, the full type declaration defines other operations whose direct use is only possible within the package itself.

If the private type declaration includes a discriminant part, the full declaration must include a discriminant part that conforms (see 6.3.1 for the conformance rules) and its type definition must be a record type definition. Conversely, if the private type declaration does not include a discriminant part, the type declared by the full type declaration (the full type) must not be an unconstrained type with discriminants. The full type must not be an unconstrained array type. A limited type (in particular a task type) is allowed for the full type only if the reserved word limited appears in the private type declaration (see 7.4.4).

Within the specification of the package that declares a private type and before the end of the corresponding full type declaration, a restriction applies to the use of a name that denotes the private type or a subtype of the private type and, likewise, to the use of a name that denotes any type or subtype that has a subcomponent of the private type. The only allowed occurrences of such a name are in a deferred constant declaration, a type or subtype declaration, a subprogram specification, or an entry declaration; moreover, occurrences within derived type definitions or within simple expressions are not allowed.

The elaboration of a private type declaration creates a private type. If the private type declaration has a discriminant part, this elaboration includes that of the discriminant part. The elaboration of the full type declaration consists of the elaboration of the type definition; the discriminant part, if any, is not elaborated (since the conforming discriminant part of the private type declaration has already been elaborated).

Notes:

It follows from the given rules that neither the declaration of a variable of a private type, nor the creation by an allocator of an object of the private type are allowed before the full declaration of the type. Similarly before the full declaration, the name of the private type cannot be used in a generic instantiation or in a representation clause.

References: allocator, array type, conform, declarative item, deferred constant declaration, derived type, discriminant part, elaboration, entry declaration, expression, full type declaration, generic instantiation, identifier, incomplete type declaration, limited type, name, operation, package, package specification, private part, private type, private type declaration, record type definition, representation clause, reserved word, subcomponent, subprogram specification, subtype, subtype declaration, type, type declaration, type definition, unconstrained array type, variable, visible part.

7.4.2. Operations of a Private Type

[PREVIOUS][UP][NEXT]

The operations that are implicitly declared by a private type declaration include basic operations. These are the operations involved in assignment (unless the reserved word limited appears in the declaration), membership tests, selected components for the selection of any discriminant, qualification, and explicit conversions.

For a private type T, the basic operations also include the attributes T'BASE (see 3.3.3) and T'SIZE (see 13.7.2). For an object A of a private type, the basic operations include the attribute A'CONSTRAINED if the private type has discriminants (see 3.7.4), and in any case, the attributes A'SIZE and A'ADDRESS (see 13.7.2).

Finally, the operations implicitly declared by a private type declaration include the predefined comparison for equality and inequality unless the reserved word limited appears in the private type declaration.

The above operations, together with subprograms that have a parameter or result of the private type and that are declared in the visible part of the package, are the only operations from the package that are available outside the package for the private type.

Within the package that declares the private type, the additional operations implicitly declared by the full type declaration are also available. However, the redefinition of these implicitly declared operations is allowed within the same declarative region, including between the private type declaration and the corresponding full declaration. An explicitly declared subprogram hides an implicitly declared operation that has the same parameter and result type profile (this is only possible if the implicitly declared operation is a derived subprogram or a predefined operator).

If a composite type has subcomponents of a private type and is declared outside the package that declares the private type, then the operations that are implicitly declared by the declaration of the composite type include all operations that only depend on the characteristics that result from the private type declaration alone. (For example the operator < is not included for a one-dimensional array type.)

If the composite type is itself declared within the package that declares the private type (including within an inner package or generic package), then additional operations that depend on the characteristics of the full type are implicitly declared, as required by the rules applicable to the composite type (for example the operator < is declared for a one-dimensional array type if the full type is discrete). These additional operations are implicitly declared at the earliest place within the immediate scope of the composite type and after the full type declaration.

The same rules apply to the operations that are implicitly declared for an access type whose designated type is a private type or a type declared by an incomplete type declaration.

For every private type or subtype T the following attribute is defined:

Note:

A private type declaration and the corresponding full type declaration define 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 and any language rule that applies only to another class of types does not apply. The fact that the full declaration might implement the private type with a type of a particular class (for example, as an array type) is only relevant within the package itself.

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 type; task dependence rules still apply to components that are task objects.

Example:

    package KEY_MANAGER is
       type KEY is private;
       NULL_KEY : constant KEY;
       procedure GET_KEY(K : out KEY);
       function "<" (X, Y : KEY) return BOOLEAN;
    private
       type KEY is new NATURAL;
       NULL_KEY : constant KEY := 0;
    end; 

    package body KEY_MANAGER is
       LAST_KEY : KEY := 0;
       procedure GET_KEY(K : out KEY) is
       begin
          LAST_KEY := LAST_KEY + 1;
          K := LAST_KEY;
       end GET_KEY; 

       function "<" (X, Y : KEY) return BOOLEAN is
       begin
          return INTEGER(X) < INTEGER(Y);
       end "<";
    end KEY_MANAGER; 

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.

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 type INTEGER is necessary to invoke the "<" operator of this type. Alternatively, the result of the function could be written as not (X >= Y), since the operator ">=" is not redefined.

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 section 7.3.)

References: assignment, attribute, basic operation, component, composite type, conversion, declaration, declarative region, derived subprogram, derived type, dimension, discriminant, equality, full type, full type declaration, hiding, immediate scope, implicit declaration, incomplete type declaration, membership test, operation, package, parameter of a subprogram, predefined function, predefined operator, private type, private type declaration, program unit, qualification, relational operator, selected component, subprogram, task dependence, visible part.

7.4.3. Deferred Constants

[PREVIOUS][UP][NEXT]

If a deferred constant declaration is given in the visible part of a package then a constant declaration (that is, an object declaration declaring a constant object, with an explicit initialization) with the same identifier must appear as a declarative item of the private part of the package. This object declaration is called the full declaration of the deferred constant. The type mark given in the full declaration must conform to that given in the deferred constant declaration (see 6.3.1). Multiple or single declarations are allowed for the deferred and the full declarations, provided that the equivalent single declarations conform.

Within the specification of the package that declares a deferred constant and before the end of the corresponding full declaration, the use of a name that denotes the deferred constant is only allowed in the default expression for a record component or for a formal parameter (not for a generic formal parameter).

The elaboration of a deferred constant declaration has no other effect.

The execution of a program is erroneous if it attempts to use the value of a deferred constant before the elaboration of the corresponding full declaration.

Note:

The full declaration for a deferred constant that has a given private type must not appear before the corresponding full type declaration. This is a consequence of the rules defining the allowed uses of a name that denotes a private type (see 7.4.1).

References: conform, constant declaration, declarative item, default expression for a discriminant, deferred constant, deferred constant declaration, elaboration has no other effect, formal parameter, generic formal parameter, and 12.3, identifier, object declaration, package, package specification, private part, record component, type mark, visible part.

7.4.4. Limited Types

[PREVIOUS][UP]

A limited type is a type for which neither assignment nor the predefined comparison for equality and inequality is implicitly declared.

A private type declaration that includes the reserved word limited declares a limited type. A task type is a limited type. A type derived from a limited type is itself a limited type. Finally, a composite type is limited if the type of any of its subcomponents is limited.

The operations available for a private type that is limited are as given in section 7.4.2 for private types except for the absence of assignment and of a predefined comparison for equality and inequality.

For a formal parameter whose type is limited and whose declaration occurs in an explicit subprogram declaration, the mode out is only allowed if this type is private and the subprogram declaration occurs within the visible part of the package that declares the private type. The same holds for formal parameters of entry declarations and of generic procedure declarations. The corresponding full type must not be limited if the mode out is used for any such formal parameter. Otherwise, the corresponding full type is allowed (but not required) to be a limited type (in particular, it is allowed to be a task type). If the full type corresponding to a limited private type is not itself limited, then assignment for the type is available within the package, but not outside.

The following are consequences of the rules for limited types:

Notes:

The above rules do not exclude a default expression for a formal parameter of a limited type; they do not exclude a deferred constant of a limited type if the full type is not limited. An explicit declaration of an equality operator is allowed for a limited type (see 6.7).

Aggregates are not available for a limited composite type (see 3.6.2 and 3.7.4). Catenation is not available for a limited array type (see 3.6.2).

Example:

    package I_O_PACKAGE is
       type FILE_NAME is limited private; 

       procedure OPEN (F : in out FILE_NAME);
       procedure CLOSE(F : in out FILE_NAME);
       procedure READ (F : in FILE_NAME; ITEM : out INTEGER);
       procedure WRITE(F : in FILE_NAME; ITEM : in  INTEGER);
    private
       type FILE_NAME is
          record
             INTERNAL_NAME : INTEGER := 0;
          end record;
    end I_O_PACKAGE; 

    package body I_O_PACKAGE is
       LIMIT : constant := 200;
       type FILE_DESCRIPTOR is record  ...  end record;
       DIRECTORY : array (1 .. LIMIT) of FILE_DESCRIPTOR;
       ...
       procedure OPEN (F : in out FILE_NAME) is  ...  end;
       procedure CLOSE(F : in out FILE_NAME) is  ...  end;
       procedure READ (F : in FILE_NAME; ITEM : out INTEGER) is ... end;
       procedure WRITE(F : in FILE_NAME; ITEM : in  INTEGER) is ... end;
    begin
       ...
    end I_O_PACKAGE; 

Notes on the example:

In the example above, an outside subprogram making use of I_O_PACKAGE may obtain a file name by calling OPEN and later use it in calls to READ and WRITE. Thus, outside the package, a file name obtained from OPEN acts as a kind of password; its internal properties (such as containing a numeric value) are not known and no other operations (such as addition or comparison of internal names) can be performed on a file name.

This example is characteristic of any case where complete control over the operations of a type is desired. Such packages serve a dual purpose. They prevent a user from making use of the internal structure of the type. They also implement the notion of an encapsulated data type where the only operations on the type are those given in the package specification.

References: aggregate, allocator, assignment, catenation operator, component declaration, component type, composite type, default expression for a discriminant, deferred constant, derived type, designate, discriminant specification, equality, formal parameter, full type, full type declaration, generic formal parameter, and 12.3, implicit declaration, initial value, mode, object, operation, package, predefined operator, private type, private type declaration, record component, record type, relational operator, subcomponent, subprogram, task type, and 9.2, type.


[INDEX][CONTENTS]