Version 1.4 of ai05s/ai05-0192-1.txt
!standard 13.1(15.2/2) 11-03-11 AI05-0192-1/02
!standard 13.13.2(8.1/2)
!standard 13.13.2(25/2)
!standard 13.13.2(50/2)
!class binding interpretation 11-02-20
!status Amendment 2012 11-03-11
!status ARG Approved 8-0-0 10-02-20
!status work item 09-11-03
!status received 09-05-11
!priority Low
!difficulty Easy
!qualifier Error
!subject Behavior of 'Input for types with constrained first subtypes
!summary
The result of 'Input is constrained if the type is composite and the
first subtype is constrained.
!question
Consider:
type T1 (D : Natural) is ... ;
type T2 is new T1 (123);
X : T1 := T1 (T2'Input (...));
Is the result subtype of T2'Input constrained? (Yes.) If so, it must raise
Constraint_Error is the discriminant is not 123.
13.13.2(50/2) says that it is, but 13.13.2(25/2) says that
13.1(15.2/2) applies - the aspect is derived, which would make the subtype
unconstrained.
Which interpretation is correct?
Another question occurs presuming that the attribute is constrained.
Is an implementation required, allowed, or forbidden to perform the constraint
check as soon as the discriminant value is read from the stream? (Anywhere.)
Would it be legal to defer the check until the end? (Yes.)
!recommendation
(See summary.)
!wording
Modify 13.13.2(8.1/2):
For an untagged derived type, the Write (resp. Read) attribute is inherited
according to the rules given in 13.1 if the attribute is {Redundant[specified
and] }available for the parent type at the point where T is declared. For a
tagged derived type, these attributes are not inherited, but rather the
default implementations are used.
Modify 13.13.2(25/2):
For an untagged derived type, the Output (resp. Input) attribute is
inherited according to the rules given in 13.1 if the attribute is
{Redundant[specified and]} available for the parent type at the point where
T is declared. For a tagged derived type, these attributes are not inherited,
but rather the default implementations are used.
Modify 13.13.2(50/2):
In the parameter_and_result_profiles for {the default implementations of} the
stream-oriented attributes, the subtype of the Item parameter is the base
subtype of T if T is a scalar type, and the first subtype otherwise. The same
rule applies to the result of the Input attribute.
AARM Discussion: An inherited stream attribute has a profile as determined by
the rules for inheriting primitive subprograms (see 13.1 and 3.4).
!discussion
13.1(15.2/2) says that inherited aspects of a derived type work the same way
as a user-defined primitive subprogram of the type. It should be obvious that
they have to work this way, as the body of the subprogram will be expecting the
constraints it was defined with, not some other constraints.
13.13.2(50/2) was intended to apply to new stream aspects but not inherited
ones. That means it applies to all tagged types and most other types as well.
We add some wording to make that clear. Also note that we never inherit the
the default implementation of the attributes; we only inherit when the attribute
is specified.
With this new wording, the answer to the first question is easy: the subtype
is constrained. But we get a different answer if we have an explicitly specified
attribute:
type T1 (D : Natural) is ...
with Input => ...;
type T2 is new T1 (123);
X : T1 := T1 (T2'Input (...));
Now the aspect is inherited, and the subtype of T2'Input is unconstrained. Note
that it is possible to inherit operations that could not have been written explicitly
-- but this is the way inherited subprograms work and we couldn't change it if
we wanted to.
On the second question, 13.13.2(36/2) applies, and is very clear. It says "at
which point" the checks are made is unspecified. So long as the exception raised
by the checks is handled by the proper handler (which is required by the infamous
11.6), the implementation is correct.
One could argue that the wording of 13.13.2(36/2) is so vague that almost anything
is allowed. But that is the intent: the wording specifically says that the number
of stream elements read cannot be predicted. So the intent is clearly that pretty
much anything sensible goes.
We could add an AARM note to the effect that we meant what we said, but that seems
silly.
!corrigendum 13.13.2(8.1/2)
Replace the paragraph:
For an untagged derived type, the Write (resp. Read) attribute is inherited
according to the rules given in 13.1 if the attribute is available for the
parent type at the point where T is declared. For a tagged derived type,
these attributes are not inherited, but rather the default implementations
are used.
by:
For an untagged derived type, the Write (resp. Read) attribute is inherited
according to the rules given in 13.1 if the attribute is specified and
available for the parent type at the point where T is declared. For
a tagged derived type, these attributes are not inherited, but rather the
default implementations are used.
!corrigendum 13.13.2(25/2)
Replace the paragraph:
For an untagged derived type, the Output (resp. Input) attribute is inherited
according to the rules given in 13.1 if the attribute is available for the
parent type at the point where T is declared. For a tagged derived type,
these attributes are not inherited, but rather the default implementations
are used.
by:
For an untagged derived type, the Output (resp. Input) attribute is inherited
according to the rules given in 13.1 if the attribute is specified and
available for the parent type at the point where T is declared. For a
tagged derived type, these attributes are not inherited, but rather the
default implementations are used.
!ACATS Test
!appendix
From: Steve Baird
Sent: Monday, May 11, 2009 4:04 PM
A question was raised at AdaCore about the Input attribute of an untagged
derived type with a constrained first subtype, as in
type T1 (D : Natural) is ... ;
type T2 is new T1 (123);
X : T1 := T1 (T2'Input (...));
Question #1:
In the above example, should Constraint_Error be raised if the
discriminant value read from the stream is not equal to 123?
The RM appears to contradict itself with respect to the definition of the result
subtype of T2'Input.
The more specific (and therefore presumably correct) applicable passage is
13.13.2(50/2), which says
In the parameter_and_result_profiles for the stream-oriented
attributes, the subtype of the Item parameter is the base subtype of
T if T is a scalar type, and the first subtype otherwise. The same
rule applies to the result of the Input attribute.
This suggests that the result subtype is constrained and that therefore
Constraint_Error should be raised. Note that the changes AI05-007 makes in this
area have no effect in the non-scalar case.
The opposing argument is based on the following chain:
13.13.2(25/2): "For an untagged derived type, the Output
(resp. Input) attribute is inherited according to the rules
given in 13.1 ..."
13.1(15.2/2): "When an aspect that is a subprogram is inherited, the
derived type inherits the aspect in the same way that a derived
type inherits a user-defined primitive subprogram from its parent
(see 3.4)."
3.4(19): "If the declaration of the derived type has neither a
known_discriminant_part nor a record_extension_part, then the
corresponding subtype has a constraint that corresponds (as defined
above for the first subtype of the derived type) to that of the
given subtype."
This suggests that the result subtype is unconstrained. I think an AARM note
resolving this apparent contradiction is all that is needed.
Question #2:
Assuming that Constraint_Error is to be raised, is an implementation
required, allowed, or forbidden to perform the constraint
check as soon as the discriminant value is read from the stream?
Would it be legal to defer the check until the end, effectively
implementing T2'Input as something like
function T2'Input (...) return T2 is
begin
return T2 (T1'Input (...));
end T2'Input;
? How about an early check something like
function T2'Input (...) return T2 is
begin
if Integer'Input (...) /= 123 then
raise Constraint_Error;
end if;
declare
Result : T2;
begin
T2'Read (Result);
return Result;
end;
end T2'Input;
? Does any of this depend on 11.6 ?
****************************************************************
From: Brad Moore
Sent: Tuesday, May 12, 2009 11:19 PM
< Question #2:
< Assuming that Constraint_Error is to be raised, is an implementation
< required, allowed, or forbidden to perform the constraint
< check as soon as the discriminant value is read from the stream?
< Would it be legal to defer the check until the end, ... ?
I would say that 13.13.2(36/2) seems to provide the answer to this question. It
states; "It is unspecified at which point and in which order these checks are
performed. In particular, if Constraint_Error is raised due to the failure of
one of these checks, it is unspecified how many stream elements have been read
from the stream."
As to the first question, I would think people would expect the constraint error
to be raised.
****************************************************************
From: Steve Baird
Sent: Wednesday, May 13, 2009 5:36 PM
> I would say that 13.13.2(36/2) seems to provide the answer to this
> question. It states; "It is unspecified at which point and in which
> order these checks are performed. In particular, if Constraint_Error
> is raised due to the failure of one of these checks, it is
> unspecified how many stream elements have been read from the stream."
I tend to agree with you.
The question here is whether the freedom you described extends across a call
boundary. In 13.1(15.2/2), presumably the phrase "in the same way" means that
3.4(27/2) defines the dynamic semantics of a call to
My_Untagged_Derived_Type'Inherited_Streaming_Attribute.
> As to the first question, I would think people would expect the
> constraint error to be raised.
Again, I agree with you.
I still think there is enough of an apparent contradiction to justify an AARM
note.
****************************************************************
Questions? Ask the ACAA Technical Agent