Version 1.11 of ai05s/ai05-0228-1.txt

Unformatted version of ai05s/ai05-0228-1.txt version 1.11
Other versions for file 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 new paragraph:
!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