3.3.1 Object Declarations
{
AI05-0262-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,
access, task, or protected object, the
object_declaration
may include the definition of the (anonymous) type of the object.
Syntax
Name Resolution Rules
Legality Rules
Static Semantics
{
AI05-0264-1}
{
AI05-0299-1}
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 subclause
7.4. The rules for full
constant declarations are given in this subclause.
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.
Discussion: {
AI95-00385-01}
The phrase “full type definition” here includes the case
of an anonymous array, access, task, or protected type.
{
AI95-00373-01}
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.
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
{
AI95-00363-01}
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 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.
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.
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:
The implicit initial value for an access subtype
is the null value of the access type.
{
AI05-0228-1}
The implicit initial value for a scalar subtype that has the Default_Value
aspect specified is the value of that aspect converted to the nominal
subtype (which might raise Constraint_Error — see
4.6,
“
Type Conversions”);
Ramification: This is a Dynamic Semantics
rule, so the visibility of the
aspect_specification
is not relevant — if the full type for a private type has the Default_Value
aspect specified, partial views of the type also have this implicit initial
value.
The implicit initial (and only) value for each
discriminant of a constrained discriminated subtype is defined by the
subtype.
{
AI05-0228-1}
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), 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,
if the composite subtype has the Default_Component_Value aspect specified,
the implicit initial value is the value of that aspect converted to the
component's nominal subtype; otherwise, any implicit initial values are
those determined by the component's nominal subtype.
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.
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.
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 cases).
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).
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.
When
an object is initialized by default, any per-object constraints (see
3.8) are elaborated and any implicit initial
values for the object or for its subcomponents are obtained as determined
by the nominal subtype.
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.
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.
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).
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.
This paragraph was deleted.{
AI95-00373-01}
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.
{
AI95-00373-01}
For the third step above, evaluations and assignments are performed in
an arbitrary order subject to the following restrictions:
{
AI95-00373-01}
Assignment to any part of the object is preceded by the evaluation of
the value that is to be assigned.
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.
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.
{
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.
Reason: For
example:
type R(D : Integer := F) is
record
S : String(1..D) := (others => G);
end record;
X : R;
For the elaboration of the declaration of X,
it is important that F be evaluated before the aggregate.
{
AI95-00373-01}
{
AI05-0092-1}
The assignments to any components, including implicit components, not
requiring late initialization 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 precede
the initial value evaluations of the component occurring later.
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:
type T (D : Natural) is
limited record
C1 : T1 (T'Access);
C2 : Natural := F (D);
C3 : String (1 .. D) := (others => ' ');
end record;
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.
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.
{
AI05-0228-1}
[There is no implicit initial value defined for a scalar subtype unless
the Default_Value aspect has been specified for the type.]
In
the absence of an explicit initialization or the specification of the
Default_Value aspect, a newly created scalar object might have a value
that does not belong to its subtype (see
13.9.1
and
H.1).
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”.
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).
13 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.
15 The type of a stand-alone object cannot
be abstract (see
3.9.3).
Examples
Example of a multiple
object declaration:
-- the multiple object declaration
-- is equivalent to the two single object declarations in the order given
{
AI95-00433-01}
John :
not null Person_Name :=
new Person(Sex => M);
Paul :
not null Person_Name :=
new Person(Sex => M);
Examples of variable
declarations:
{
AI95-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 String := "Hi, world.";
θ, φ : Float
range -π .. +π;
Examples of constant
declarations:
{
AI95-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
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.
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
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
{
AI95-00363-01}
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
Wording Changes from Ada 95
{
8652/0002}
{
AI95-00171-01}
Corrigendum: Corrected wording to say that per-object constraints
are elaborated (not evaluated).
{
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.
Extensions to Ada 2005
Wording Changes from Ada 2005
{
AI05-0228-1}
Implicit initial values can now be given for scalar types and for scalar
array components, using the Default_Value (see
3.5)
and Default_Component_Value (see
3.6) aspects;
the extension is documented there.
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe