Version 1.1 of ais/ai-00195.txt

Unformatted version of ais/ai-00195.txt version 1.1
Other versions for file ais/ai-00195.txt

!standard 13.13.1 (00)          98-03-27 AI95-00195/01
!class binding interpretation 98-03-27
!status received 98-03-27
!priority High
!difficulty Hard
!subject Streams
!summary 98-03-27
!question 98-03-27
!recommendation 98-03-27
!wording 98-03-27
!discussion 98-03-27

!section 13.13.1
!subject Various issues with the stream-oriented attributes
!reference RM95 13.13.1
!reference RM95 13.13.2
!reference AI95-00108
!from Pascal Leroy 97-09-02
!reference 1997-15783.a Pascal Leroy 1997-9-2>>

1 - RM95 13.13.2(27) states that S'Input "creates an object (with the bounds
or discriminants, if any, taken from the stream), initializes it with S'Read,
and returns the value of the object.

Does the verb "initialize" in this sentence refer to the entire initialization
process mentioned in RM95 3.3.1(18) and 7.6(10)? In particular, if S is a
controlled subtype, or if it contains controlled components, is the Initialize
subprogram called?  Is the Finalize subprogram called when the intermediate
object is finalized?  For a record type whose components have initial values,
are these values evaluated?

It seems that the simplest model is that S'Input declares a local object,
which is then passed to S'Read, as in:

                X : S (<discriminants taken from the stream>);
                S'Read (..., X);

If we don't do that, the object passed to S'Read might have uninitialized
access values, or uninitialized compiler-specific fields (dopes, offsets, tag,

2 - RM95 13.13.2(36) states that "an attribute_reference for one of these
attributes is illegal if the type is limited, unless the attribute has been
specified by an attribute definition clause."

If some stream-oriented attribute has been specified in a private part, and we
are at a point that doesn't have visibility over that private part, is a
reference to the attribute legal? For example:

        package P is
                type T is limited private;
                procedure Read (Stream : ...; Item : out T);
                for T'Read use Read;
        end P;

        with P;
        procedure Q is
                X : T;
                T'Read (..., X);        -- Legal?
        end Q;

One hopes that the call to T'Read is illegal, overwise it would break the
privacy of private types.

3 - Let T a limited type with an attribute_definition_clause for attribute
Read, and D a type derived from T, and assume that there is no attribute
definition clause for D'Read:

        type T is limited record ... end record;
        for T'Read use ...;

        type D is new T;

Is a usage of D'Read legal or not?  In other words, shall we consider that,
for the purpose of checking RM95 13.13.2(36), "an attribute has been
specified" for D?

If the answer is "yes", how do the inheritance rules stated in AI95-00108
apply in the case where T is tagged, and D has a component of a task type in
its record extension part?  How is an implementation expected to read that

4 - The definition of the profiles of the predefined S'Read, S'Write, S'Input
and S'Read given in RM95 13.13.2 uses the notation "T italic" for the type of
the Item parameter.  AI95-00145 explains that:

"The italicized T shown in the definitions of predefined operators means:

     - T'Base, for scalars
     - the first subtype, for tagged types
     - the type without any constraint, in other cases"

(Note that the above sentence says "operators", so strictly speaking it
doesn't apply to attributes; it seems that the wording of this AI should be

When one of these attributes is specified by an attribute definition clause,
RM95 13.13.2(36) states that "the subtype of the Item parameter shall be the
base subtype if scalar, and the first subtype otherwise."

There is a problem because these definitions don't coincide in the case of
constrained array types.  Consider:

        type T is new String (1 .. 10);

It appears that the type of the Item parameter of the predefined
stream-oriented attributes is "T without any constraint" (an anonymous
unconstrained array type ), while the type of the Item parameter for a
user-defined stream-oriented subprogram is T.

In particular, does the presence or absence of an attribute definition clause
have any bearing on the legality of the calls?  For example, consider the
legality of the 'others' choice in an array aggregate; it depends on the
existence on an applicable index constraint, and therefore on whether the type
of the parameter is constrained or not:

        package P is
                type T is new String (1 .. 10);
                procedure Write (...; Item : in T);
                for T'Write use Write;
        end P;

        with P;
        procedure Q is
                T'Write (..., (others => 'a')); -- Legal?

Is the above call legal? If yes, would it become illegal if the
attribute_definition_clause were removed?

A possible model is to say that an attribute_definition_clause changes the
body of the Read attribute, but not its profile.  It's as if the predefined
Read was just a wrapper calling the user-specified subprogram.

5 - AI95-00108 states (in the !discussion section) that "for untagged derived
types, there is no problem for the derived type inheriting the stream

This doesn't seem clear if the derived type includes a known discriminant
part.  Consider:

        type Parent (D1, D2 : Integer := 1) is ...;
        type Child (D : Integer := 2) is new Parent (D1 => D, D2 => D);

Clearly Parent'Write writes two discriminant values.  It would seem that
Child'Write should only write one discriminant value, which contradicts the
simple inheritance rule given in the AI.

6 - RM95 13.13.2(9) states that for a record type, the predefined S'Read reads
the components in positional aggregate order.  However, the RM95 doesn't seem
to specify what happens when exceptions are raised by the calls to the Read
attribute for the components.  Consider for example the following type

        type T1 is range ...;
        type T2 is range ...;

        type R (D1 : T1 := ...; D2 : T2 := ...) is
                end record;

Say that attributes_definition_clauses have been given for T1'Read and
T2'Read, and consider the call:

        X : R;
        R'Read (..., X);

Assume that an exception is raised by T2'Read.  Is the discriminant X.D1
modified?  That would be unpleasant if there were components depending on this

Consider a different example, where there are no discriminants:

        type T1 is ...;
        type T2 is ...;

        type R is
                        C1 : T1;
                        C2 : T2;
                end record;

Assume that an exception is raised by T2'Read.  Is the component X.C1

It would seem that we should stick to the notion that discriminants are only
modified by an assignment of entire objects.  This probably requires an
intermediate object in the case of discriminated types.  However, it would
seem quite expensive to require the creation of such an intermediate object
for types that don't have discriminants.

Note that if we adopt the idea that an intermediate object is needed (at least
in some cases) then we must define if initialization and finalization of this
object take place.

7 - Consider a call to T'Read where T is a type with defaulted discriminants.
 If the discriminants found in the stream have values different from those of
the discriminants of the object passed to T'Read for the Item parameter, and
that object is constrained, is Constraint_Error raised?

Note that if we adopt the model that an intermediate object is needed in this
case, then the constraint check performed when assigning the intermediate
object to the actual parameter will raise Constraint_Error.

8 - If T is an abstract type, is the function T'Input abstract?  One hopes so,
otherwise it makes it possible to create objects of an abstract type.

9 - RM95 13.13.1(1) states that "T'Read and T'Write make dispatching calls on
the Read and Write procedures of the type Root_Stream_Type."

Is the number of those calls specified?  For example, for the predefined
implementation of String'Write, is an implementation required to call
Ada.Streams.Write for each character? or is it allowed to perform internal
buffering and to call Ada.Streams.Write only once for the entire string?
 Obviously the user could tell the difference by writing a pervert
implementation of the Write subprogram, but it would seem that performance
considerations should have the priority in this case.

Pascal Leroy                                    +                             + FAX


!section 13.13.2(17)
!subject Stream size of 16 bit integers
!reference RM95 13.13.2 (17)
!reference 1998-15826.a Stephen Leake 98-03-14
!reference 1998-15827.a Tucker Taft 1998-3-17
!from Randy Brukardt 98-03-18
!keywords base type, size clause, stream representation
!reference 1998-15828.a Randy Brukardt  1998-3-19>>

We just ran into this problem.  We were trying to use Streams to read
Microsoft Windows bitmap files.  Since the file format is defined external
to Ada, and is not very friendly to Ada, it is fairly difficult.  We tried
various stearm solutions that worked on GNAT, but not on ObjectAda, because
of the 16-bit vs. 32-bit problem.  Since we can't control the stream
representation, we can't use Streams to portably read this externally
defined file format.

We ended up reading an array of Storage_Elements, then converting that with
Unchecked_Conversion.  Yuk!

This problem should be solved; otherwise, Ada 95 will not be able to
portably read files with a definition outside of Ada.



Questions? Ask the ACAA Technical Agent