Version 1.11 of ai05s/ai05-0228-1.txt
!standard 3.3.1(11) 11-05-05 AI05-0228-1/05
!standard 3.3.1(13)
!standard 3.3.1(21)
!standard 3.5(56/2)
!standard 3.6(22/2)
!standard 6.4.1(13)
!standard 13.13.2(35/2)
!class Amendment 10-10-22
!status Amendment 2012 11-03-11
!status ARG Approved 7-0-0 11-02-19
!status work item 10-10-22
!status received 10-10-22
!priority Medium
!difficulty Easy
!subject Default initial values for scalar and array types
!summary
Two new aspects are added to provide default initial values for scalar types
and arrays of scalar types.
!problem
The new predicate (see AI05-0153-3) and invariant (see AI05-0146-1) aspects
provide unreliable results for objects that are not initialized. This can be
prevented when a default initial value is provided.
It is easy to provide a default initial value for record types, and access types
have one defined by the language, but for other kinds of types, it is
impossible.
This seems bizarre, given that implementations have the capability of doing
default initialization (as for record and access types).
!proposal
Add an aspect Default_Value that can be used on all scalar types, and an
additional aspect Default_Component_Value that can be used on all array of scalar
types.
!wording
Add a new bullet after 3.3.1(11):
* 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”);
AARM 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.
Modify 3.3.1(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, {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.
[Editor's note: We delete the cross-reference because it has been moved into the new
bullet; we don't repeat cross-references in paragraphs that will be read together.]
Modify 3.3.1(21):
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).
Add after 3.5(56/2):
Static Semantics
For a scalar type, the following language-defined representation aspect
may be specified with an aspect_specification:
Default_Value
This aspect shall be specified by a static expression, and that
expression shall be explicit, even if the aspect has a boolean type.
Default_Value shall be specified only on a full_type_declaration.
AARM Reason: The part about requiring an explicit expression is to disallow
omitting the value for this aspect, which would otherwise be allowed by the
rules of 13.3.1.
This is a representation aspect in order to disallow specifying it on a
derived type that has inherited primitive subprograms; that is necessary as
the sizes of out parameters could be different whether or not a Default_Value
is specified (see 6.4.1).
End AARM Reason.
If a derived type with no primitive subprograms inherits a boolean Default_Value
aspect, the aspect may be specified to have any value for the derived type.
AARM Reason: This is to override the 13.3.1 rule that says that a boolean aspect
with a value True cannot be changed.
Name Resolution
The expected type for the expression specified for the Default_Value aspect is
the type defined by the full_type_declaration on which it appears.
Add after 3.6(22/2):
Static Semantics
For an array type with a scalar component type, the following
language-defined representation aspect may be specified with an
aspect_specification:
Default_Component_Value
This aspect shall be specified by a static expression, and that
expression shall be explicit, even if the aspect has a boolean type.
Default_Component_Value shall be specified only on a full_type_declaration.
AARM Reason: The part about requiring an explicit expression is to disallow
omitting the value for this aspect, which would otherwise be allowed by the
rules of 13.3.1.
If a derived type with no primitive subprograms inherits a boolean Default_Value
aspect, the aspect may be specified to have any value for the derived type.
AARM Reason: This is to override the 13.3.1 rule that says that a boolean aspect
with a value True cannot be changed for a derived type.
Name Resolution
The expected type for the expression specified for the Default_Component_Value aspect
is the component type of the array type defined by the full_type_declaration on which
it appears.
Add a new bullet after 6.4.1(13): [Note that 6.4.1(13) was modified by AI05-0196-1 --
we echo that wording here, not the original wording.]
* For a scalar type that has the Default_Value aspect specified, the formal parameter
is initialized from the value of the actual, without checking that the value satisfies
any constraint;
AARM Reason: This preserves the language design principle that all objects of a type
with an implicit initial value are initialized. This is important so that a programmer
can guarantee that all objects of a scalar type have a valid value with a carefully
chosen Default_Value.
AARM Implementation Note: This rule means that out parameters of a subtype T with
a specified Default_Value need to be large enough to support any possible value of the
base type of T. In contrast, a type that does not have a Default_Value only need
support the size of the subtype (since no values are passed in).
[Editor's note: We don't need to modify the composite rule, as the changed definition
of "implicit initial values" effectively changes this rule to include arrays with
a specified Default_Component_Value.]
Modify AARM 6.4.1(15.a):
This case covers scalar types {that do not have Default_Value specified}, and composite
types whose subcomponent's subtypes do not have any implicit initial values. The
view conversion for composite types ensures that if the lengths don't match between
an actual and a formal array parameter, the Constraint_Error is raised before the call,
rather than after.
Modify 13.13.2(35/2):
In the default implementation of Read and Input for a composite type, for each scalar
component that is a discriminant or [whose component_declaration includes a
default_expression]{that has an implicit initial value}, a check is made that the value
returned by Read for the component belongs to its subtype. Constraint_Error is raised if
this check fails. For other scalar components, no check is made. For each component that
is of an access type, if the implementation can detect that the value returned by Read
for the component is not a value of its subtype, Constraint_Error is raised. If the
value is not a value of its subtype and this error is not detected, the component has
an abnormal value, and erroneous execution can result (see 13.9.1). In the default
implementation of Read for a composite type with defaulted discriminants, if the actual
parameter of Read is constrained, a check is made that the discriminants read from the
stream are equal to those of the actual parameter. Constraint_Error is raised if this
check fails.
AARM To Be Honest: An implementation should always be able to detect the
error for a null value read into an access subtype with a null exclusion; the "if the
implementation can detect" is intended to cover non-null access values.
AARM Ramification: A scalar component can have an implicit initial value if it has a
default_expression, if the component's type has the Default_Value aspect specified,
or if the component is that of an array type that has the Default_Component_Value
aspect specified.
!discussion
It is important that the default initial value be something that makes sense for
the type. Simply initializing everything to zero is just as likely to cover bugs
as eliminate them.
However, if a type has a value specifically that means "Unknown" or "Undefined",
it makes perfect sense to initialize all objects to that value. That would
greatly reduce the chances of invalid objects of the type existing.
We considered making these subtype aspects rather than type aspects. That would
allow giving different default values to different subtypes. However, given the
existence of many ways to create anonymous subtypes it would be very hard to
guarantee that all values of a type are initialized. Without that guarantee, these
aspects lose a lot of their purpose.
!examples
Providing a default initial value for an enumeration type with an unknown value:
type Item_State is (Unknown, Fooey, Blarch, ...) with Default_Value => Unknown;
Providing string type that is initialized with blanks:
type Blank_String is array (Positive range <>) of Character with
Default_Component_Value => ' ';
!corrigendum 3.3.1(11)
Insert after the paragraph:
- The implicit initial value for an access subtype is the null value of the
access type.
the new paragraph:
- 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");
!corrigendum 3.3.1(13)
Replace the paragraph:
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.
by:
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.
!corrigendum 3.3.1(21)
Replace the paragraph:
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).
by:
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).
!corrigendum 3.5(56/2)
Insert after the paragraph:
An implementation may extend the Wide_Wide_Value, Wide_Value, Value, Wide_Wide_Image,
Wide_Image, and Image attributes of a floating point type to support special values
such as infinities and NaNs.
the new paragraphs:
Static Semantics
For a scalar type, the following language-defined representation aspect
may be specified with an aspect_specification (see 13.1.1):
- Default_Value
-
This aspect shall be specified by a static expression, and that
expression shall be explicit, even if the aspect has a boolean type.
Default_Value shall be specified only on a full_type_declaration.
If a derived type with no primitive subprograms inherits a boolean Default_Value
aspect, the aspect may be specified to have any value for the derived type.
Name Resolution Rules
The expected type for the expression specified for the Default_Value aspect is
the type defined by the full_type_declaration on which it appears.
!corrigendum 3.6(22)
Insert after the paragraph:
The elaboration of a discrete_subtype_definition that does not contain any
per-object expressions creates the discrete subtype, and consists of the elaboration
of the subtype_indication or the evaluation of the range. The elaboration
of a discrete_subtype_definition that contains one or more per-object expressions
is defined in 3.8. The elaboration of a component_definition in an
array_type_definition consists of the elaboration of the subtype_indication
or access_definition. The elaboration of any discrete_subtype_definitions
and the elaboration of the component_definition are performed in an arbitrary order.
the new paragraphs:
Static Semantics
For an array type with a scalar component type, the following
language-defined representation aspect may be specified with an
aspect_specification (see 13.1.1):
- Default_Component_Value
-
This aspect shall be specified by a static expression, and that
expression shall be explicit, even if the aspect has a boolean type.
Default_Component_Value shall be specified only on a full_type_declaration.
If a derived type with no primitive subprograms inherits a boolean Default_Component_Value
aspect, the aspect may be specified to have any value for the derived type.
Name Resolution Rules
The expected type for the expression specified for the Default_Component_Value aspect
is the component type of the array type defined by the full_type_declaration on
which it appears.
!corrigendum 6.4.1(13)
Insert after the paragraph:
For an access type, the formal parameter is initialized from the value of the actual,
without a constraint check;
the new paragraph:
For a scalar type that has the Default_Value aspect specified, the formal parameter
is initialized from the value of the actual, without checking that the value satisfies
any constraint;
!corrigendum 13.13.2(35)
Replace the paragraph:
In the default implementation of Read and Input for a composite type, for each
scalar component that is a discriminant or whose component_declaration
includes a default_expression, a check is made that the value returned by
Read for the component belongs to its subtype. Constraint_Error is raised if
this check fails. For other scalar components, no check is made. For each
component that is of an access type, if the implementation can detect that
the value returned by Read for the component is not a value of its subtype,
Constraint_Error is raised. If the value is not a value of its subtype and
this error is not detected, the component has an abnormal value, and erroneous
execution can result (see 13.9.1). In the default implementation of Read for a
composite type with defaulted discriminants, if the actual parameter of Read is
constrained, a check is made that the discriminants read from the stream are
equal to those of the actual parameter. Constraint_Error is raised if this
check fails.
by:
In the default implementation of Read and Input for a composite type, for each
scalar component that is a discriminant or that has an implicit initial value,
a check is made that the value returned by
Read for the component belongs to its subtype. Constraint_Error is raised if
this check fails. For other scalar components, no check is made. For each
component that is of an access type, if the implementation can detect that
the value returned by Read for the component is not a value of its subtype,
Constraint_Error is raised. If the value is not a value of its subtype and
this error is not detected, the component has an abnormal value, and erroneous
execution can result (see 13.9.1). In the default implementation of Read for a
composite type with defaulted discriminants, if the actual parameter of Read is
constrained, a check is made that the discriminants read from the stream are
equal to those of the actual parameter. Constraint_Error is raised if this
check fails.
!ACATS test
ACATS tests would be needed for this aspect.
!appendix
[Editor's note: This thread forked off of a discussion of predicates.]
From: Robert Dewar
Sent: Wednesday, October 13, 2010 11:21 AM
> Well, yeah. We get a lot of support calls about uninit vars.
> Too bad there's no language feature to prevent those bugs.
All language features that "fix" uninitialized variables are evil. Requiring
default initialization or providing default implicit initialization are
particularly evil in my view.
****************************************************************
From: Bob Duff
Sent: Wednesday, October 13, 2010 12:33 PM
> All language features that "fix" uninitialized variables are evil.
I won't touch that with a barge pole. ;-)
Anyway, it's irrelevant to my point, which is that uninit vars are a loophole in
constraints, so the argument "predicates must be loophole-free, because
constraints are" is bogus.
>... Requiring default initialization or providing default implicit
>initialization are particularly evil in my view.
I certainly agree with that.
Too bad JDI didn't (I'm talking about access types).
****************************************************************
From: Tucker Taft
Sent: Wednesday, October 13, 2010 1:01 PM
>> ... Requiring default initialization or providing default implicit
>> initialization are particularly evil in my view.
>
> I certainly agree with that.
>
> Too bad JDI didn't (I'm talking about access types).
The default initial value of "null" for an access type seems OK, since you get
an exception if you try to use it as though it had a usable non-null value.
It is a default initial value of zero that is dangerous, since it is not
distinguishable from a "true" initial value of zero. If there were a "null"
value for all types, which corresponded roughly to a floating point signaling
NaN, that would be fine in my view. You would get notified if you tried to do
anything that presumed the object had an "intentional" initial value.
****************************************************************
From: Randy Brukardt
Sent: Wednesday, October 13, 2010 1:50 PM
Right. The annoying thing is that Ada doesn't have a way to set a default
initial value for scalar and array types, for those cases where there is an
"obviously" bad value. For instance, many of my enumeration types have an value
of "unknown" or something like that. It's purpose is exactly to provide a value
for those cases where something has gone wrong or nothing has been calculated
yet. Typically, it would be used (manually of course) as a default initial value
for objects; it would be nice to be able to force all objects to start with that
value rather than random garbage. Ada compilers clearly have the mechanism to
deal with default initializations (because of access types and record
components), so it is annoying that the programmer can't use that when it is
appropriate.
****************************************************************
From: Robert Dewar
Sent: Wednesday, October 13, 2010 5:29 PM
TW, on the IM 7040, there was a great instruction intended only for system
diagnostics to set parity wrong on a specified word.
WATFor fortran used this to initialize all uninitialized variables (under some
option flag). And you got a parity error if you tried to load the value.
BTW, I don't think it is worth spending too much time on different checking
modes. Compilers will likely provide different checking modes anyway, whatever
the standard says.
****************************************************************
From: Robert Dewar
Sent: Wednesday, October 13, 2010 5:27 PM
>> It is a default initial value of zero that is dangerous, since it is
>> not distinguishable from a "true" initial value of zero. If there
>> were a "null" value for all types, which corresponded roughly to a
>> floating point signaling NaN, that would be fine in my view. You
>> would get notified if you tried to do anything that presumed the
>> object had an "intentional" initial value.
Big overhead in the array case having to check, and the trouble is that you MUST
be able to have 32 tc integers, represented in the obvious way. It would be a
menace if Ada insisted on stealing one value.
> Ada
> compilers clearly have the mechanism to deal with default
> initializations (because of access types and record components), so it
> is annoying that the programmer can't use that when it is appropriate.
Good point, I think I will invent a pragma. In fact the obvious pragma to extend
is
pragma Initialize_Scalars;
and allow the usage
pragma Initialize_Scalars (local_type_NAME);
20 minutes work to allow this!
****************************************************************
From: Randy Brukardt
Sent: Wednesday, October 13, 2010 5:44 PM
> >> It is a default initial value of zero that is dangerous, since it
> >> is not distinguishable from a "true" initial value of zero. If
> >> there were a "null" value for all types, which corresponded roughly
> >> to a floating point signaling NaN, that would be fine in my view.
> >> You would get notified if you tried to do anything that presumed
> >> the object had an "intentional" initial value.
>
> Big overhead in the array case having to check, and the trouble is
> that you MUST be able to have 32 tc integers, represented in the
> obvious way. It would be a menace if Ada insisted on stealing one
> value.
I agree that it doesn't make sense to do it in all cases; it's just odd to not
have the capability when it is useful. [That's Tucker's quote, BTW.]
> > Ada
> > compilers clearly have the mechanism to deal with default
> > initializations (because of access types and record components), so
> > it is annoying that the programmer can't use that when it is appropriate.
>
> Good point, I think I will invent a pragma. In fact the obvious pragma
> to extend is
>
> pragma Initialize_Scalars;
>
> and allow the usage
>
> pragma Initialize_Scalars (local_type_NAME);
>
> 20 minutes work to allow this!
At one point, someone suggested having an aspect for this purpose. That would
look something like:
type Item_State is (Unknown, Fooey, Blarch, ...) with Default_Initial_Value => Unknown;
This seems like a good use for an aspect, given that it isn't something that
ought to be dependent on the view of the type (or subtype, if we wanted to allow
that).
The (minor) advantage of the aspect over the pragma is that it allows the
default value to be specified; that might be helpful if the "Unknown" value is
not the first one in the enumeration.
****************************************************************
From: Robert Dewar
Sent: Wednesday, October 13, 2010 6:00 PM
Well we could allow a default value for Initialize_Scalars or some other pragma.
IS in GNAT is not always the lowest value, and can in fact be changed at link
time or even execution time (the idea is to try different initial values and see
if has an observable effect
A disadvantage of an aspect if that is the only mechanism is that it is
restricted to Ada 2012 mode. We have a lot of customers still stuck at Ada 95
(partly because of the high level of incompatibility between Ada 95 and Ada
2005).
****************************************************************
From: Tucker Taft
Sent: Wednesday, October 13, 2010 6:10 PM
I believe we already discussed something along these lines in the recent ARG
meeting. Didn't we invent an aspect spec like "with Default => blah"? Or am I
dreaming that?
****************************************************************
From: Randy Brukardt
Sent: Wednesday, October 13, 2010 6:37 PM
I think we invented it, but I don't think anyone took ownership of it and got it
added to the agenda. As such, it is now too late (it wasn't included in the
scope approved by WG 9), unless someone can figure out a reason why we need to
add it for one of the existing AIs.
****************************************************************
From: Robert Dewar
Sent: Wednesday, October 13, 2010 6:47 PM
Sounds good to me, I think I will implement the aspect and the corresponding
pragma, so it really doesn't matter too much if it gets into the standard. It's
a good idea!
****************************************************************
From: Jean-Pierre Rosen
Sent: Thursday, October 14, 2010 3:48 AM
I was about to suggest an aspect too, but Randy shot first...
> A disadvantage of an aspect if that is the only mechanism is that it
> is restricted to Ada 2012 mode. We have a lot of customers still stuck
> at Ada 95 (partly because of the high level of incompatibility between
> Ada 95 and Ada 2005).
OTOH, people will move to the new versions if the benefits balance the
disagreements. Providing nice features in the most recent modes is a way to push
them.
****************************************************************
From: Robert Dewar
Sent: Thursday, October 14, 2010 6:13 PM
Well in fact in GNAT we systematically provide pragmas to match all aspects in
any case, the way the internal implementation of aspects work is to translate to
the corresponding pragma or attribute definition clause. So for example, we now
have pragma predicate and pragma invariant in GNAT.
We are more in the business of providing useful features to people than pushing
them to use the latest version of Ada. As I say, the biggest barrier is the
rather fierce upwards incompatibility of Ada 2005, this has resulted in a
barrier for several large users (the issue with return of limited stuff).
We have talked about a mode which would provide Ada 95 + all compatible
features, but this is quite a bit of work.
****************************************************************
Questions? Ask the ACAA Technical Agent