Go to the first, previous, next, last section, table of contents.


Packages

  1. Packages are program units that allow the specification of groups of logically related entities. Typically, a package contains the declaration of a type (often a private type or private extension) along with the declarations of primitive subprograms of the type, which can be called from outside the package, while their inner workings remain hidden from outside users.

Package Specifications and Declarations

  1. A package is generally provided in two parts: a package_specification and a package_body. Every package has a package_specification, but not all packages have a package_body. Syntax
  2. package_declaration ::= package_specification;
    
  3. package_specification ::=
       package defining_program_unit_name is
          {basic_declarative_item}
       [private
          {basic_declarative_item}]
       end [[parent_unit_name.]identifier]
    
    1. If an identifier or parent_unit_name.identifier appears at the end of a package_specification, then this sequence of lexical elements shall repeat the defining_program_unit_name.

Legality Rules

  1. A package_declaration or generic_package_declaration requires a completion (a body) if it contains any declarative_item that requires a completion, but whose completion is not in its package_specification. Static Semantics
  2. The first list of declarative_items of a package_specification of a package other than a generic formal package is called the visible part of the package. The optional list of declarative_items after the reserved word private (of any package_specification) is called the private part of the package. If the reserved word private does not appear, the package has an implicit empty private part.
  3. An entity declared in the private part of a package is visible only within the declarative region of the package itself (including any child units -- see section Compilation Units - Library Units. In contrast, expanded names denoting entities declared in the visible part can be used even outside the package; furthermore, direct visibility of such entities can be achieved by means of use_clauses, see section Selected Components, and section Use Clauses. Dynamic Semantics
  4. The elaboration of a package_declaration consists of the elaboration of its basic_declarative_items in the given order. NOTES
  5. (1) The visible part of a package contains all the information that another program unit is able to know about the package.
  6. (2) If a declaration occurs immediately within the specification of a package, and the declaration has a corresponding completion that is a body, then that body has to occur immediately within the body of the package. Examples
  7. Example of a package declaration:
  8. package Rational_Numbers is
    
  9. type Rational is
       record
          Numerator   : Integer;
          Denominator : Positive;
       end record;
    
  10.    function "="(X,Y : Rational) return Boolean;
    
  11.    function "/"  (X,Y : Integer)  return Rational;
       --  to construct a rational number
    
  12.    function "+"  (X,Y : Rational) return Rational;
       function "-"  (X,Y : Rational) return Rational;
       function "*"  (X,Y : Rational) return Rational;
       function "/"  (X,Y : Rational) return Rational;
    end Rational_Numbers;
    
  13. There are also many examples of package declarations in the predefined language environment, see section Predefined Language Environment (normative).

Package Bodies

  1. In contrast to the entities declared in the visible part of a package, the entities declared in the package_body are visible only within the package_body itself. As a consequence, a package with a package_body can be used for the construction of a group of related subprograms in which the logical operations available to clients are clearly isolated from the internal entities. Syntax
  2. package_body ::=
       package body defining_program_unit_name is
          declarative_part
       [begin
          handled_sequence_of_statements]
       end [[parent_unit_name.]identifier];
    
    1. If an identifier or parent_unit_name.identifier appears at the end of a package_body, then this sequence of lexical elements shall repeat the defining_program_unit_name.

Legality Rules

  1. A package_body shall be the completion of a previous package_declaration or generic_package_declaration. A library package_declaration or library generic_package_declaration shall not have a body unless it requires a body; pragma Elaborate_Body can be used to require a library_unit_declaration to have a body, see section Elaboration Control, if it would not otherwise require one. Static Semantics
  2. In any package_body without statements there is an implicit null_statement. For any package_declaration without an explicit completion, there is an implicit package_body containing a single null_statement. For a noninstance, nonlibrary package, this body occurs at the end of the declarative_part of the innermost enclosing program unit or block_statement; if there are several such packages, the order of the implicit package_bodies is unspecified. (For an instance, the implicit package_body occurs at the place of the instantiation, See section Generic Instantiation. For a library package, the place is partially determined by the elaboration dependences, see section Program Structure and Compilation Issues. Dynamic Semantics
  3. For the elaboration of a nongeneric package_body, its declarative_part is first elaborated, and its handled_sequence_of_statements is then executed. NOTES
  4. (3) A variable declared in the body of a package is only visible within this body and, consequently, its value can only be changed within the package_body. In the absence of local tasks, the value of such a variable remains unchanged between calls issued from outside the package to subprograms declared in the visible part. The properties of such a variable are similar to those of a "static" variable of C.
  5. (4) The elaboration of the body of a subprogram explicitly declared in the visible part of a package is caused by the elaboration of the body of the package. Hence a call of such a subprogram by an outside program unit raises the exception Program_Error if the call takes place before the elaboration of the package_body, see section Declarative Parts. Examples
  6. Example of a package body, see section Package Specifications and Declarations
  7. package body Rational_Numbers is
    
  8.    procedure Same_Denominator (X,Y : in out Rational) is
       begin
          --  reduces X and Y to the same denominator:
          ...
       end Same_Denominator;
    
  9.    function "="(X,Y : Rational) return Boolean is
          U : Rational := X;
          V : Rational := Y;
       begin
          Same_Denominator (U,V);
          return U.Numerator = V.Numerator;
       end "=";
    
  10.    function "/" (X,Y : Integer) return Rational is
       begin
          if Y > 0 then
             return (Numerator => X,  Denominator => Y);
          else
             return (Numerator => -X, Denominator => -Y);
          end if;
       end "/";
    
  11.    function "+" (X,Y : Rational) return Rational is ...  end "+";
       function "-" (X,Y : Rational) return Rational is ...  end "-";
       function "*" (X,Y : Rational) return Rational is ...  end "*";
       function "/" (X,Y : Rational) return Rational is ...  end "/";
    
  12. end Rational_Numbers;
    

Private Types and Private Extensions

  1. 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 section Type Extensions, for an overview of type extensions. Syntax
  2. private_type_declaration ::=
       type defining_identifier [discriminant_part] is
         [[abstract] tagged] [limited] private;
    
  3. private_extension_declaration ::=
       type defining_identifier [discriminant_part] is
         [abstract] new ancestor_subtype_indication with private;
    
    Legality Rules
  4. A private_type_declaration or private_extension_declaration declares a partial view of the type; such a declaration is allowed only as a declarative_item of the visible part of a package, and it requires a completion, which shall be a full_type_declaration that occurs as a declarative_item of the private part of the package. The view of the type declared by the full_type_declaration is called the full view. A generic formal private type or a generic formal private extension is also a partial view.
  5. A type shall be completely defined before it is frozen, see section Completions of Declarations, and section Freezing Rules. 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.
  6. A private type is limited if its declaration includes the reserved word limited; a private extension is limited if its ancestor type is limited. 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.
  7. 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.
  8. 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 section Generic Instantiation, the requirement that the ancestor be specific applies also in the private part of an instance of a generic unit.
  9. If the declaration of a partial view includes a known_discriminant_part, then the full_type_declaration shall have a fully conforming (explicit) known_discriminant_part, see section Conformance Rules. The ancestor subtype may be unconstrained; the parent subtype of the full view is required to be constrained, see section Discriminants.
  10. 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.
  11. If a partial view has unknown discriminants, then the full_type_declaration may define a definite or an indefinite subtype, with or without discriminants.
  12. If a partial view has neither known nor unknown discriminants, then the full_type_declaration shall define a definite subtype.
  13. 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
  14. A private_type_declaration declares a private type and its first subtype. Similarly, a private_extension_declaration declares a private extension and its first subtype.
  15. 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 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 section Private Operations.
  16. A private extension inherits components (including discriminants unless there is a new discriminant_part specified) and user-defined primitive subprograms from its ancestor type, in the same way that a record extension inherits components and user-defined primitive subprograms from its parent type, see section Derived Types and Classes. Dynamic Semantics
  17. The elaboration of a private_type_declaration creates a partial view of a type. The elaboration of a private_extension_declaration elaborates the ancestor_subtype_indication, and creates a partial view of a type. NOTES
  18. (5) 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 might or might not be composite. A private extension is also composite, as is its full view.
  19. (6) 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. If such a type is also limited, then no objects of the type can be declared outside the scope of the full_type_declaration, restricting all object creation to the package defining the type. This allows complete control over all storage allocation for the type. Objects of such a type can still be passed as parameters, however.
  20. (7) 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 need not be the same -- 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 section Dispatching Operations of Tagged Types. Examples
  21. Examples of private type declarations:
  22. type Key is private;
    type File_Name is limited private;
    
  23. Example of a private extension declaration:
  24. type List is new Ada.Finalization.Controlled with private;
    

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. 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. For a composite type, the characteristics, see section Private Types and Private Extensions 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 within 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. The corresponding rule applies to a type defined by a derived_type_definition, if there is a place within its immediate scope where additional characteristics of its parent type become visible.
  5. 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 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. 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, within the immediate scope of the type_declaration, 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.
  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.
    
    NOTES
  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 section Representation Attributes. For an object A of a partial view, the attributes A'Size and A'Address are defined, see section Representation Attributes. 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 section Deferred Constants
       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;
    
    NOTES
  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 See section Package Bodies.)

Deferred Constants

  1. Deferred constant declarations may be used to declare constants in the visible part of a package, but with the value of the constant given in the private part. They may also be used to declare constants imported from other languages, see section Interface to Other Languages (normative). Legality Rules
  2. A deferred constant declaration is an object_declaration with the reserved word constant but no initialization expression. The constant declared by a deferred constant declaration is called a deferred constant. A deferred constant declaration requires a completion, which shall be a full constant declaration (called the full declaration of the deferred constant), or a pragma Import. See section Interface to Other Languages (normative).
  3. A deferred constant declaration that is completed by a full constant declaration shall occur immediately within the visible part of a package_ specification. For this case, the following additional rules apply to the corresponding full declaration:
    1. The full declaration shall occur immediately within the private part of the same package;
    2. The deferred and full constants shall have the same type;
    3. If the subtype defined by the subtype_indication in the deferred declaration is constrained, then the subtype defined by the subtype_indication in the full declaration shall match it statically. On the other hand, if the subtype of the deferred constant is unconstrained, then the full declaration is still allowed to impose a constraint. The constant itself will be constrained, like all constants;
    4. If the deferred constant declaration includes the reserved word aliased, then the full declaration shall also.
  1. A deferred constant declaration that is completed by a pragma Import need not appear in the visible part of a package_specification, and has no full constant declaration.
  2. The completion of a deferred constant declaration shall occur before the constant is frozen, see section Deferred Constants. Dynamic Semantics
  3. The elaboration of a deferred constant declaration elaborates the subtype_indication or (only allowed in the case of an imported constant) the array_type_definition. NOTES
  4. (12) The full constant declaration for a deferred constant that is of a given private type or private extension is not allowed before the corresponding full_type_declaration. This is a consequence of the freezing rules for types, see section Freezing Rules. Examples
  5. Examples of deferred constant declarations:
  6. Null_Key : constant Key;      --  see section Private Operations
    
  7. CPU_Identifier : constant String(1..8);
    pragma Import(Assembler, CPU_Identifier, Link_Name => "CPU_ID");
    --  see section Interfacing Pragmas
    

Limited Types

  1. A limited type is (a view of) a type for which the assignment operation is not allowed. A nonlimited type is a (view of a) type for which the assignment operation is allowed. Legality Rules
  2. If a tagged record type has any limited components, then the reserved word limited shall appear in its record_type_definition. Static Semantics
  3. A type is limited if it is a descendant of one of the following:
    1. a type with the reserved word limited in its definition;
    2. a task or protected type;
    3. a composite type with a limited component.
  1. Otherwise, the type is nonlimited.
  2. There are no predefined equality operators for a limited type. NOTES
  3. (13) The following are consequences of the rules for limited types:
    1. An initialization expression is not allowed in an object_declaration if the type of the object is limited.
    2. A default expression is not allowed in a component_declaration if the type of the record component is limited.
    3. An initialized allocator is not allowed if the designated type is limited.
    4. A generic formal parameter of mode in must not be of a limited type.
  1. (14) Aggregates are not available for a limited composite type. Concatenation is not available for a limited array type.
  2. (15) The 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 declaration of the constant is of a nonlimited type.
  3. (16) As illustrated in section Private Operations, an untagged limited type can become nonlimited under certain circumstances. Examples
  4. Example of a package with a limited type:
  5. package IO_Package is
       type File_Name is limited private;
    
  6.    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
          limited record
             Internal_Name : Integer := 0;
          end record;
    end IO_Package;
    
  7. package body IO_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 IO_Package;
    
    NOTES
  8. (17) Notes on the example: In the example above, an outside subprogram making use of IO_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. Most importantly, clients of the package cannot make copies of objects of type File_Name.
  9. 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.
  10. The fact that the full view of File_Name is explicitly declared limited means that parameter passing and function return will always be by reference, see section Formal Parameter Modes, and section Return Statements.

User-Defined Assignment and Finalization

  1. Three kinds of actions are fundamental to the manipulation of objects: initialization, finalization, and assignment. Every object is initialized, either explicitly or by default, after being created (for example, by an object_declaration or allocator). Every object is finalized before being destroyed (for example, by leaving a subprogram_body containing an object_declaration, or by a call to an instance of Unchecked_Deallocation). An assignment operation is used as part of assignment_statements, explicit initialization, parameter passing, and other operations.
  2. Default definitions for these three fundamental operations are provided by the language, but a controlled type gives the user additional control over parts of these operations. In particular, the user can define, for a controlled type, an Initialize procedure which is invoked immediately after the normal default initialization of a controlled object, a Finalize procedure which is invoked immediately before finalization of any of the components of a controlled object, and an Adjust procedure which is invoked as the last step of an assignment to a (nonlimited) controlled object. Static Semantics
  3. The following language-defined library package exists:
  4. package Ada.Finalization is
        pragma Preelaborate(Finalization);
    
  5.     type Controlled is abstract tagged private;
    
  6.     procedure Initialize(Object : in out Controlled);
        procedure Adjust                 (Object : in out Controlled);
        procedure Finalize               (Object : in out Controlled);
    
  7.     type Limited_Controlled is abstract tagged limited private;
    
  8.     procedure Initialize(Object : in out Limited_Controlled);
        procedure Finalize  (Object : in out Limited_Controlled);
    private
        ... -- not specified by the language
    end Ada.Finalization;
    
  9. A controlled type is a descendant of Controlled or Limited_Controlled. The (default) implementations of Initialize, Adjust, and Finalize have no effect. The predefined "=" operator of type Controlled always returns True, since this operator is incorporated into the implementation of the predefined equality operator of types derived from Controlled, as explained in section Relational Operators and Membership Tests. The type Limited_Controlled is like Controlled, except that it is limited and it lacks the primitive subprogram Adjust. Dynamic Semantics
  10. During the elaboration of an object_declaration, for every controlled subcomponent of the object that is not assigned an initial value (as defined in 3.3.1), Initialize is called on that subcomponent. Similarly, if the object as a whole is controlled and is not assigned an initial value, Initialize is called on the object. The same applies to the evaluation of an allocator, as explained in section Allocators.
  11. For an extension_aggregate whose ancestor_part is a subtype_mark, Initialize is called on all controlled subcomponents of the ancestor part; if the type of the ancestor part is itself controlled, the Initialize procedure of the ancestor type is called, unless that Initialize procedure is abstract.
  12. Initialize and other initialization operations are done in an arbitrary order, except as follows. Initialize is applied to an object after initialization of its subcomponents, if any (including both implicit initialization and Initialize calls). If an object has a component with an access discriminant constrained by a per-object expression, Initialize is applied to this component after any components that do not have such discriminants. For an object with several components with such a discriminant, Initialize is applied to them in order of their component_declarations. For an allocator, any task activations follow all calls on Initialize.
  13. When a target object with any controlled parts is assigned a value, either when created or in a subsequent assignment_statement, the assignment operation proceeds as follows:
    1. The value of the target becomes the assigned value.
    2. The value of the target is adjusted.
  1. To adjust the value of a (nonlimited) composite object, the values of the components of the object are first adjusted in an arbitrary order, and then, if the object is controlled, Adjust is called. Adjusting the value of an elementary object has no effect, nor does adjusting the value of a composite object with no controlled parts.
  2. For an assignment_statement, after the name and expression have been evaluated, and any conversion (including constraint checking) has been done, an anonymous object is created, and the value is assigned into it; that is, the assignment operation is applied. (Assignment includes value adjustment.) The target of the assignment_statement is then finalized. The value of the anonymous object is then assigned into the target of the assignment_statement. Finally, the anonymous object is finalized. As explained below, the implementation may eliminate the intermediate anonymous object, so this description subsumes the one given in See section Assignment Statements. Implementation Permissions
  3. An implementation is allowed to relax the above rules (for nonlimited controlled types) in the following ways:
    1. For an assignment_statement that assigns to an object the value of that same object, the implementation need not do anything.
    2. For an assignment_statement for a noncontrolled type, the implementation may finalize and assign each component of the variable separately (rather than finalizing the entire variable and assigning the entire new value) unless a discriminant of the variable is changed by the assignment.
    3. For an aggregate or function call whose value is assigned into a target object, the implementation need not create a separate anonymous object if it can safely create the value of the aggregate or function call directly in the target object. Similarly, for an assignment_statement, the implementation need not create an anonymous object if the value being assigned is the result of evaluating a name denoting an object (the source object) whose storage cannot overlap with the target. If the source object might overlap with the target object, then the implementation can avoid the need for an intermediary anonymous object by exercising one of the above permissions and perform the assignment one component at a time (for an overlapping array assignment), or not at all (for an assignment where the target and the source of the assignment are the same object). Even if an anonymous object is created, the implementation may move its value to the target object as part of the assignment without re-adjusting so long as the anonymous object has no aliased subcomponents.

Completion and Finalization

  1. This subclause defines completion and leaving of the execution of constructs and entities. A master is the execution of a construct that includes finalization of local objects after it is complete (and after waiting for any local tasks -- see section Task Dependence - Termination of Tasks.), but before leaving. Other constructs and entities are left immediately upon completion. Dynamic Semantics
  2. The execution of a construct or entity is complete when the end of that execution has been reached, or when a transfer of control, see section Simple and Compound Statements - Sequences of Statements, causes it to be abandoned. Completion due to reaching the end of execution, or due to the transfer of control of an exit_, return_, goto_, or requeue_statement or of the selection of a terminate_alternative is normal completion. Completion is abnormal otherwise -- when control is transferred out of a construct due to abort or the raising of an exception.
  3. After execution of a construct or entity is complete, it is left, meaning that execution continues with the next action, as defined for the execution that is taking place. Leaving an execution happens immediately after its completion, except in the case of a master: the execution of a task_body, a block_statement, a subprogram_body, an entry_body, or an accept_statement. A master is finalized after it is complete, and before it is left.
  4. For the finalization of a master, dependent tasks are first awaited, as explained in section Task Dependence - Termination of Tasks. Then each object whose accessibility level is the same as that of the master is finalized if the object was successfully initialized and still exists. These actions are performed whether the master is left by reaching the last statement or via a transfer of control. When a transfer of control causes completion of an execution, each included master is finalized in order, from innermost outward.
  5. For the finalization of an object:
    1. If the object is of an elementary type, finalization has no effect;
    2. If the object is of a controlled type, the Finalize procedure is called;
    3. If the object is of a protected type, the actions defined in section Protected Units and Protected Objects are performed;
    4. If the object is of a composite type, then after performing the above actions, if any, every component of the object is finalized in an arbitrary order, except as follows: if the object has a component with an access discriminant constrained by a per-object expression, this component is finalized before any components that do not have such discriminants; for an object with several components with such a discriminant, they are finalized in the reverse of the order of their component_declarations.
  1. Immediately before an instance of Unchecked_Deallocation reclaims the storage of an object, the object is finalized. If an instance of Unchecked_Deallocation is never applied to an object created by an allocator, the object will still exist when the corresponding master completes, and it will be finalized then.
  2. The order in which the finalization of a master performs finalization of objects is as follows: Objects created by declarations in the master are finalized in the reverse order of their creation. For objects that were created by allocators for an access type whose ultimate ancestor is declared in the master, this rule is applied as though each such object that still exists had been created in an arbitrary order at the first freezing point, see section Freezing Rules, of the ultimate ancestor type.
  3. The target of an assignment statement is finalized before copying in the new value, as explained in section User-Defined Assignment and Finalization.
  4. The anonymous objects created by function calls and by aggregates are finalized no later than the end of the innermost enclosing declarative_item or statement; if that is a compound_statement, they are finalized before starting the execution of any statement within the compound_statement. Bounded (Run-Time) Errors
  5. It is a bounded error for a call on Finalize or Adjust to propagate an exception. The possible consequences depend on what action invoked the Finalize or Adjust operation:
    1. For a Finalize invoked as part of an assignment_statement, Program_Error is raised at that point.
    2. For an Adjust invoked as part of an assignment operation, any other adjustments due to be performed are performed, and then Program_Error is raised.
    3. For a Finalize invoked as part of a call on an instance of Unchecked_Deallocation, any other finalizations due to be performed are performed, and then Program_Error is raised.
    4. For a Finalize invoked by the transfer of control of an exit_, return_, goto_, or requeue_statement, Program_Error is raised no earlier than after the finalization of the master being finalized when the exception occurred, and no later than the point where normal execution would have continued. Any other finalizations due to be performed up to that point are performed before raising Program_Error.
    5. For a Finalize invoked by a transfer of control that is due to raising an exception, any other finalizations due to be performed for the same master are performed; Program_Error is raised immediately after leaving the master.
    6. For a Finalize invoked by a transfer of control due to an abort or selection of a terminate alternative, the exception is ignored; any other finalizations due to be performed are performed.
    NOTES
  1. (18) The rules of See section Program Structure and Compilation Issues, imply that immediately prior to partition termination, Finalize operations are applied to library-level controlled objects (including those created by allocators of library-level access types, except those already finalized). This occurs after waiting for library-level tasks to terminate.
  2. (19) A constant is only constant between its initialization and finalization. Both initialization and finalization are allowed to change the value of a constant.
  3. (20) Abort is deferred during certain operations related to controlled types, as explained in section Abort of a Task - Abort of a Sequence of Statements. Those rules prevent an abort from causing a controlled object to be left in an ill-defined state.
  4. (21) The Finalize procedure is called upon finalization of a controlled object, even if Finalize was called earlier, either explicitly or as part of an assignment; hence, if a controlled type is visibly controlled (implying that its Finalize primitive is directly callable), or is nonlimited (implying that assignment is allowed), its Finalize procedure should be designed to have no ill effect if it is applied a second time to the same object.


Go to the first, previous, next, last section, table of contents.