[Home] [Prev] [Next] [Index]

3.3 Objects and Named Numbers

3.3 Objects and Named Numbers

1
[Objects are created at run time and contain a value of a given type. An object can be created and initialized as part of elaborating a declaration, evaluating an allocator, aggregate, or function_call, or passing a parameter by copy. Prior to reclaiming the storage for an object, it is finalized if necessary (see 7.6.1).]

Static Semantics

2
All of the following are objects:

2.a
Glossary entry: An object is either a constant or a variable. An object contains a value. An object is created by an object_declaration or by an allocator. A formal parameter is (a view of) an object. A subcomponent of an object is an object.

3 ·
the entity declared by an object_declaration;

4 ·
a formal parameter of a subprogram, entry, or generic subprogram;

5 ·
a generic formal object;

6 ·
a loop parameter;

7 ·
a choice parameter of an exception_handler;

8 ·
an entry index of an entry_body;

9 ·
the result of dereferencing an access-to-object value (see 4.1);

10 ·
the result of evaluating a function_call (or the equivalent operator invocation - see 6.6);

11 ·
the result of evaluating an aggregate;

12 ·
a component, slice, or view conversion of another object.

13
An object is either a constant object or a variable object. The value of a constant object cannot be changed between its initialization and its finalization, whereas the value of a variable object can be changed. Similarly, a view of an object is either a constant or a variable.  All views of a constant object are constant. A constant view of a variable object cannot be used to modify the value of the variable.  The terms constant and variable by themselves refer to constant and variable views of objects.

14
The value of an object is read when the value of any part of the object is evaluated, or when the value of an enclosing object is evaluated. The value of a variable is updated when an assignment is performed to any part of the variable, or when an assignment is performed to an enclosing object.

14.a
Ramification: Reading and updating are intended to include read/write references of any kind, even if they are not associated with the evaluation of a particular construct.  Consider, for example, the expression "X.all(F)", where X is an access-to-array object, and F is a function. The implementation is allowed to first evaluate "X.all" and then F. Finally, a read is performed to get the value of the F'th component of the array. Note that the array is not necessarily read as part of the evaluation of "X.all". This is important, because if F were to free X using Unchecked_Deallocation, we want the execution of the final read to be erroneous.

15
Whether a view of an object is constant or variable is determined by the definition of the view. The following (and no others) represent constants:

16 ·
an object declared by an object_declaration with the reserved word constant;

17 ·
a formal parameter or generic formal object of mode in;

18 ·
a discriminant;

19 ·
a loop parameter, choice parameter, or entry index;

20 ·
the dereference of an access-to-constant value;

21 ·
the result of evaluating a function_call or an aggregate;

22 ·
a selected_component, indexed_component, slice, or view conversion of a constant.

22.a
To be honest: A noninvertible view conversion to a general access type is also defined to be a constant - see 4.6.

23
At the place where a view of an object is defined, a nominal subtype is associated with the view. The object's actual subtype (that is, its subtype) can be more restrictive than the nominal subtype of the view; it always is if the nominal subtype is an indefinite subtype. A subtype is an indefinite subtype if it is an unconstrained array subtype, or if it has unknown discriminants or unconstrained discriminants without defaults (see 3.7); otherwise the subtype is a definite subtype [(all elementary subtypes are definite subtypes)]. [A class-wide subtype is defined to have unknown discriminants, and is therefore an indefinite subtype. An indefinite subtype does not by itself provide enough information to create an object; an additional constraint or explicit initialization expression is necessary (see 3.3.1). A component cannot have an indefinite nominal subtype.]

24
A named number provides a name for a numeric value known at compile time.  It is declared by a number_declaration.

NOTES

25 5
A constant cannot be the target of an assignment operation, nor be passed as an in out or out parameter, between its initialization and finalization, if any.

26 6
The nominal and actual subtypes of an elementary object are always the same.  For a discriminated or array object, if the nominal subtype is constrained then so is the actual subtype.

Extensions to Ada 83

26.a
There are additional kinds of objects (choice parameters and entry indices of entry bodies).

26.b
The result of a function and of evaluating an aggregate are considered (constant) objects.  This is necessary to explain the action of finalization on such things. Because a function_call is also syntactically a name (see 4.1), the result of a function_call can be renamed, thereby allowing repeated use of the result without calling the function again.

Wording Changes From Ada 83

26.c
This clause and its subclauses now follow the clause and subclauses on types and subtypes, to cut down on the number of forward references.

26.d
The term nominal subtype is new.  It is used to distinguish what is known at compile time about an object's constraint, versus what its "true" run-time constraint is.

26.e
The terms definite and indefinite (which apply to subtypes) are new. They are used to aid in the description of generic formal type matching, and to specify when an explicit initial value is required in an object_declaration.

26.f
We have moved the syntax for object_declaration and number_declaration down into their respective subclauses, to keep the syntax close to the description of the associated semantics.

26.g
We talk about variables and constants here, since the discussion is not specific to object_declarations, and it seems better to have the list of the kinds of constants juxtaposed with the kinds of objects.

26.h
We no longer talk about indirect updating due to parameter passing. Parameter passing is handled in 6.2 and 6.4.1 in a way that there is no need to mention it here in the definition of read and update. Reading and updating now includes the case of evaluating or assigning to an enclosing object.

3.3.1 Object Declarations

1
An object_declaration declares a stand-alone object with a given nominal subtype and, optionally, an explicit initial value given by an initialization expression. For an array, task, or protected object, the object_declaration may include the definition of the (anonymous) type of the object.

Syntax

2
object_declaration ::=
    defining_identifier_list : [aliased] [constant] subtype_indication [:= expression];
  | defining_identifier_list : [aliased] [constant] array_type_definition [:= expression];
  | single_task_declaration
  | single_protected_declaration

3
defining_identifier_list ::=
  defining_identifier {, defining_identifier}

Name Resolution Rules

4
For an object_declaration with an expression following the compound delimiter :=, the type expected for the expression is that of the object. This expression is called the initialization expression.

Legality Rules

5
An object_declaration without the reserved word constant declares a variable object.  If it has a subtype_indication or an array_type_definition that defines an indefinite subtype, then there shall be an initialization expression. An initialization expression  shall not be given if the object is of a limited type.

Static Semantics

6
An object_declaration with the reserved word constant declares a constant object. If it has an initialization expression, then it is called a full constant declaration. Otherwise it is called a deferred constant declaration. The rules for deferred constant declarations are given in clause 7.4.  The rules for full constant declarations are given in this subclause.

7
Any declaration that includes a defining_identifier_list with more than one defining_identifier is equivalent to a series of declarations each containing one defining_identifier from the list, with the rest of the text of the declaration copied for each declaration in the series, in the same order as the list. The remainder of this International Standard relies on this equivalence; explanations are given for declarations with a single defining_identifier.

8
The subtype_indication or full type definition of an object_declaration defines the nominal subtype of the object. The object_declaration declares an object of the type of the nominal subtype.

8.a
Discussion:  The phrase "full type definition" here includes the case of an anonymous array, task, or protected type.

Dynamic Semantics

9
If a composite object declared by an object_declaration has an unconstrained nominal subtype, then if this subtype is indefinite or the object is constant or aliased (see 3.10) the actual subtype of this object is constrained. The constraint is determined by the bounds or discriminants (if any) of its initial value; the object is said to be constrained by its initial value. [In the case of an aliased object, this initial value may be either explicit or implicit; in the other cases, an explicit initial value is required.] When not constrained by its initial value, the actual and nominal subtypes of the object are the same. If its actual subtype is constrained, the object is called a constrained object.

10
For an object_declaration without an initialization expression, any initial values for the object or its subcomponents are determined by the implicit initial values defined for its nominal subtype, as follows:

11 ·
The implicit initial value for an access subtype is the null value of the access type.

12 ·
The implicit initial (and only) value for each discriminant of a constrained discriminated subtype is defined by the subtype.

13 ·
For a (definite) composite subtype, the implicit initial value of each component with a default_expression is obtained by evaluation of this expression and conversion to the component's nominal subtype (which might raise Constraint_Error - see 4.6, "Type Conversions"), unless the component is a discriminant of a constrained subtype (the previous case), or is in an excluded variant (see 3.8.1). For each component that does not have a default_expression, any implicit initial values are those determined by the component's nominal subtype.

14 ·
For a protected or task subtype, there is an implicit component (an entry queue) corresponding to each entry, with its implicit initial value being an empty queue.

14.a
Implementation Note: The implementation may add implicit components for its own use, which might have implicit initial values. For a task subtype, such components might represent the state of the associated thread of control.  For a type with dynamic-sized components, such implicit components might be used to hold the offset to some explicit component.

15
The elaboration of an object_declaration proceeds in the following sequence of steps:

16 1.
The subtype_indication, array_type_definition, single_task_declaration, or single_protected_declaration is first elaborated. This creates the nominal subtype (and the anonymous type in the latter three cases).

17 2.
If the object_declaration includes an initialization expression, the (explicit) initial value is obtained by evaluating the expression and converting it to the nominal subtype (which might raise Constraint_Error - see 4.6).

18 3.
The object is created, and, if there is not an initialization expression, any per-object expressions (see 3.8) are evaluated and any implicit initial values for the object or for its subcomponents are obtained as determined by the nominal subtype.

18.a
Discussion:  For a per-object constraint that contains some per-object expressions and some non-per-object expressions, the values used for the constraint consist of the values of the non-per-object expressions evaluated at the point of the type_declaration, and the values of the per-object expressions evaluated at the point of the creation of the object.

18.b
The elaboration of per-object constraints was presumably performed as part of the dependent compatibility check in Ada 83. If the object is of a limited type with an access discriminant, the access_definition is elaborated at this time (see 3.7).

18.c
Reason: The reason we say that evaluating an explicit initialization expression happens before creating the object is that in some cases it is impossible to know the size of the object being created until its initial value is known, as in "X: String := Func_Call(...);". The implementation can create the object early in the common case where the size can be known early, since this optimization is semantically neutral.

19 4.
Any initial values (whether explicit or implicit) are assigned to the object or to the corresponding subcomponents. As described in 5.2 and 7.6, Initialize and Adjust procedures can be called.

19.a
Ramification: Since the initial values have already been converted to the appropriate nominal subtype, the only Constraint_Errors that might occur as part of these assignments are for values outside their base range that are used to initialize unconstrained numeric subcomponents.  See 3.5.

20
For the third step above, the object creation and any elaborations and evaluations are performed in an arbitrary order, except that if the default_expression for a discriminant is evaluated to obtain its initial value, then this evaluation is performed before that of the default_expression for any component that depends on the discriminant, and also before that of any default_expression that includes the name of the discriminant. The evaluations of the third step and the assignments of the fourth step are performed in an arbitrary order, except that each evaluation is performed before the resulting value is assigned.

20.a
Reason: For example:

20.b
type R(D : Integer := F) is
    record
        S : String(1..D) := (others => G);
    end record;

20.c
X : R;

20.d
For the elaboration of the declaration of X, it is important that F be evaluated before the aggregate.

21
[There is no implicit initial value defined for a scalar subtype.] In the absence of an explicit initialization, a newly created scalar object might have a value that does not belong to its subtype (see 13.9.1 and H.1).

21.a
To be honest: It could even be represented by a bit pattern that doesn't actually represent any value of the type at all, such as an invalid internal code for an enumeration type, or a NaN for a floating point type. It is a generally a bounded error to reference scalar objects with such "invalid representations", as explained in 13.9.1, "Data Validity".

21.b
Ramification: There is no requirement that two objects of the same scalar subtype have the same implicit initial "value" (or representation). It might even be the case that two elaborations of the same object_declaration produce two different initial values. However, any particular uninitialized object is default-initialized to a single value (or invalid representation). Thus, multiple reads of such an uninitialized object will produce the same value each time (if the implementation chooses not to detect the error).

NOTES

22 7
Implicit initial values are not defined for an indefinite subtype, because if an object's nominal subtype is indefinite, an explicit initial value is required.

23 8
As indicated above, a stand-alone object is an object declared by an object_declaration. Similar definitions apply to "stand-alone constant" and "stand-alone variable." A subcomponent of an object is not a stand-alone object, nor is an object that is created by an allocator. An object declared by a loop_parameter_specification, parameter_specification, entry_index_specification, choice_parameter_specification, or a formal_object_declaration is not called a stand-alone object.

24 9
The type of a stand-alone object cannot be abstract (see 3.9.3).

Examples

25
Example of a multiple object declaration:

26
--  the multiple object declaration

27
John, Paul : Person_Name := new Person(Sex => M);  --  see 3.10.1

28
--  is equivalent to the two single object declarations in the order given

29
John : Person_Name := new Person(Sex => M);
Paul : Person_Name := new Person(Sex => M);

30
Examples of variable declarations:

31
Count, Sum  : Integer;
Size        : Integer range 0 .. 10_000 := 0;
Sorted      : Boolean := False;
Color_Table : array(1 .. Max) of Color;
Option      : Bit_Vector(1 .. 10) := (others => True);
Hello       : constant String := "Hi, world.";

32
Examples of constant declarations:

33
Limit     : constant Integer := 10_000;
Low_Limit : constant Integer := Limit/10;
Tolerance : constant Real := Dispersion(1.15);

Extensions to Ada 83

33.a
The syntax rule for object_declaration is modified to allow the aliased reserved word.

33.b
A variable declared by an object_declaration can be constrained by its initial value; that is, a variable of a nominally unconstrained array subtype, or discriminated type without defaults, can be declared so long as it has an explicit initial value. In Ada 83, this was permitted for constants, and for variables created by allocators, but not for variables declared by object_declarations.  This is particularly important for tagged class-wide types, since there is no way to constrain them explicitly, and so an initial value is the only way to provide a constraint.  It is also important for generic formal private types with unknown discriminants.

33.c
We now allow an unconstrained_array_definition in an object_declaration. This allows an object of an anonymous array type to have its bounds determined by its initial value. This is for uniformity: If one can write "X: constant array(Integer range 1..10) of Integer := ...;" then it makes sense to also allow "X: constant array(Integer range <>) of Integer := ...;". (Note that if anonymous array types are ever sensible, a common situation is for a table implemented as an array. Tables are often constant, and for constants, there's usually no point in forcing the user to count the number of elements in the value.)

Wording Changes From Ada 83

33.d
We have moved the syntax for object_declarations into this subclause.

33.e
Deferred constants no longer have a separate syntax rule, but rather are incorporated in object_declaration as constants declared without an initialization expression.

3.3.2 Number Declarations

1
A number_declaration declares a named number.

1.a
Discussion:  If a value or other property of a construct is required to be static that means it is required to be determined prior to execution.  A static expression is an expression whose value is computed at compile time and is usable in contexts where the actual value might affect the legality of the construct. This is fully defined in clause 4.9.

Syntax

2
number_declaration ::=
     defining_identifier_list : constant := static_expression;

Name Resolution Rules

3
The static_expression given for a number_declaration is expected to be of any numeric type.

Legality Rules

4
The static_expression given for a number declaration shall be a static expression, as defined by clause 4.9.

Static Semantics

5
The named number denotes a value of type universal_integer if the type of the static_expression is an integer type. The named number denotes a value of type universal_real if the type of the static_expression is a real type.

6
The value denoted by the named number is the value of the static_expression, converted to the corresponding universal type.

Dynamic Semantics

7
The elaboration of a number_declaration has no effect.

7.a
Proof: Since the static_expression was evaluated at compile time.

Examples

8
Examples of number declarations:

9
Two_Pi        : constant := 2.0*Ada.Numerics.Pi;   -- a real number (see A.5)

10
Max           : constant := 500;                   -- an integer number
Max_Line_Size : constant := Max/6                  -- the integer 83
Power_16      : constant := 2**16;                 -- the integer 65_536
One, Un, Eins : constant := 1;                     -- three different names for 1

Extensions to Ada 83

10.a
We now allow a static expression of any numeric type to initialize a named number.  For integer types, it was possible in Ada 83 to use 'Pos to define a named number, but there was no way to use a static expression of some non-universal real type to define a named number.  This change is upward compatible because of the preference rule for the operators of the root numeric types.

Wording Changes From Ada 83

10.b
We have moved the syntax rule into this subclause.

10.c
AI-00263 describes the elaboration of a number declaration in words similar to that of an object_declaration.  However, since there is no expression to be evaluated and no object to be created, it seems simpler to say that the elaboration has no effect.



[Home] [Prev] [Next] [Index]

documentation@rational.com
Copyright © 1993-1998, Rational Software Corporation.   All rights reserved.