3.3.1 Object Declarations
1
{stand-alone object}
{explicit initial
value} {initialization
expression} An
object_declaration
declares a
stand-alone object with a given nominal subtype and,
optionally, an explicit initial value given by an initialization expression.
{anonymous array type} {anonymous
task type} {anonymous
protected type} For an array, task, or
protected object, the
object_declaration may
include the definition of the (anonymous) type of the object.
Syntax
2/2
{
AI95-00385-01}
{
AI95-00406-01}
object_declaration ::=
defining_identifier_list : [
aliased] [
constant]
subtype_indication [:=
expression];
| defining_identifier_list : [aliased] [constant] access_definition [:= 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
{expected type (object_declaration
initialization expression) [partial]} For
an
object_declaration with an
expression
following the compound delimiter :=, the type expected for the
expression
is that of the object.
{initialization
expression} This
expression
is called the
initialization expression.
{constructor:
See initialization expression}
Legality Rules
5/2
{
AI95-00287-01}
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.
{full
constant declaration} If it has an initialization
expression, then it is called a
full constant declaration.
{deferred
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/2
{
AI95-00385-01}
{nominal subtype} The
subtype_indication,
access_definition, 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/2
Discussion: {
AI95-00385-01}
The phrase “full type definition” here includes the case
of an anonymous array,
access, task, or
protected type.
8.1/2
{
AI95-00373-01}
{requires late
initialization} A component of an object
is said to require late initialization if it has an access discriminant
value constrained by a per-object expression, or if it has an initialization
expression that includes a name denoting the current instance of the
type or denoting an access discriminant.
8.b/2
Reason: Such components
can depend on the values of other components of the object. We want to
initialize them as late and as reproducibly as possible.
Dynamic Semantics
9/2
{
AI95-00363-01}
{constraint (of an object)}
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;
{constrained by its initial value}
the object is said to be
constrained by its initial
value.
{actual subtype (of an object)}
{subtype (of an object):
See actual subtype of an object} [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.
{constrained
(object)} {unconstrained
(object)} If its actual subtype is constrained,
the object is called a
constrained object.
10
{implicit
initial values (for a subtype)} 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).
{implicit subtype conversion (component
defaults) [partial]} 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
{elaboration
(object_declaration) [partial]} The elaboration
of an
object_declaration proceeds in the following
sequence of steps:
16/2
1.
{
AI95-00385-01}
The
subtype_indication,
access_definition, array_type_definition,
single_task_declaration, or
single_protected_declaration
is first elaborated. This creates the nominal subtype (and the anonymous
type in the
last four 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).
{implicit
subtype conversion (initialization expression) [partial]}
18/2
3.
{
8652/0002} {
AI95-00171-01}
{
AI95-00373-01}
The object is created, and, if there is not an initialization expression,
the object is initialized by default. {initialized
by default} When an object is initialized
by default, any per-object
constraints expressions
(see
3.8) are
elaborated evaluated
and any implicit initial values for the object or for its subcomponents
are obtained as determined by the nominal subtype.
{initialization (of an object)}
{assignment operation
(during elaboration of an object_declaration)} 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. {constructor: See initialization}
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/2
This paragraph
was deleted.4.
{
AI95-00373-01}
{initialization
(of an object)} {assignment
operation (during elaboration of an object_declaration)} 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. {constructor: See initialization}
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/2
{
AI95-00373-01}
For the third step above,
the
object creation and any elaborations and evaluations
and
assignments are performed in an arbitrary order
subject to the following restrictions:,
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.1/2
- {AI95-00373-01}
Assignment to any part of the object is preceded
by the evaluation of the value that is to be assigned.
20.a.1/2
Reason: Duh. But
we ought to say it. Note that, like any rule in the International Standard,
it doesn't prevent an “as-if” optimization; as long as the
semantics as observed from the program are correct, the compiler can
generate any code it wants.
20.2/2
- {AI95-00373-01}
The evaluation of a default_expression
that includes the name of a discriminant is preceded by the assignment
to that discriminant.
20.a.2/2
Reason: Duh again.
But we have to say this, too. It's odd that Ada 95 only required the
default expressions to be evaluated before the discriminant is used;
it says nothing about discriminant values that come from subtype_indications.
20.3/2
- {AI95-00373-01}
The evaluation of the default_expression
for any component that depends on a discriminant is preceded by the assignment
to that discriminant.
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.
20.4/2
- {AI95-00373-01}
The assignments to any components, including implicit
components, not requiring late initialization must precede the initial
value evaluations for any components requiring late initialization; if
two components both require late initialization, then assignments to
parts of the component occurring earlier in the order of the component
declarations must precede the initial value evaluations of the component
occurring later.
20.e/2
Reason:
Components that require late initialization can refer to the entire
object during their initialization. We want them to be initialized as
late as possible to reduce the chance that their initialization depends
on uninitialized components. For instance:
20.f/2
type T (D : Natural) is
limited record
C1 : T1 (T'Access);
C2 : Natural := F (D);
C3 : String (1 .. D) := (others => ' ');
end record;
20.g/2
Component C1 requires
late initialization. The initialization could depend on the values of
any component of T, including D, C2, or C3. Therefore, we want to it
to be initialized last. Note that C2 and C3 do not require late initialization;
they only have to be initialized after D.
20.h/2
It is possible for there
to be more than one component that requires late initialization. In this
case, the language can't prevent problems, because all of the components
can't be the last one initialized. In this case, we specify the order
of initialization for components requiring late initialization; by doing
so, programmers can arrange their code to avoid accessing uninitialized
components, and such arrangements are portable. Note that if the program
accesses an uninitialized component, 13.9.1
defines the execution to be erroneous.
21
[There is no implicit initial value defined for a
scalar subtype.]
{uninitialized variables
[partial]} 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).
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
{stand-alone
constant} {stand-alone
variable} 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/2
{
AI-00433-01}
John, Paul :
not null Person_Name :=
new Person(Sex => M); --
see 3.10.1
28
-- is equivalent to the two single object declarations in the order given
29/2
{
AI-00433-01}
John :
not null Person_Name :=
new Person(Sex => M);
Paul :
not null Person_Name :=
new Person(Sex => M);
30
Examples of variable
declarations:
31/2
{
AI-00433-01}
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 :
aliased constant String := "Hi, world.";
θ, φ : Float range -π .. +π;
32
Examples of constant
declarations:
33/2
{
AI-00433-01}
Limit :
constant Integer := 10_000;
Low_Limit :
constant Integer := Limit/10;
Tolerance :
constant Real := Dispersion(1.15);
Hello_Msg : constant access String := Hello'Access; -- see 3.10.2
Extensions to Ada 83
33.a
{
extensions to Ada 83}
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.
Inconsistencies With Ada 95
33.f/2
{
AI95-00363-01}
{inconsistencies with Ada 95} Unconstrained
aliased objects of types with discriminants with defaults are no longer
constrained by their initial values. This means that a program that raised
Constraint_Error from an attempt to change the discriminants will no
longer do so. The change only affects programs that depended on the raising
of Constraint_Error in this case, so the inconsistency is unlikely to
occur outside of the ACATS. This change may however cause compilers to
implement these objects differently, possibly taking additional memory
or time. This is unlikely to be worse than the differences caused by
any major compiler upgrade.
Extensions to Ada 95
33.g/2
{
AI95-00287-01}
{extensions to Ada 95} A
constant may have a limited type; the initialization expression
has to be built-in-place (see 7.5).
33.h/2
Wording Changes from Ada 95
33.i/2
{
8652/0002}
{
AI95-00171-01}
Corrigendum: Corrected wording to say that
per-object constraints are elaborated (not evaluated).
33.j/2
{
AI95-00373-01}
The rules for evaluating default initialization
have been tightened. In particular, components whose default initialization
can refer to the rest of the object are required to be initialized last.
33.k/2