13.13.2 Stream-Oriented Attributes
{
8652/0009}
{
AI95-00137-01}
{
AI05-0183-1}
The type-related operational attributes Write, Read, Output, and Input
convert values to a stream of elements and reconstruct values from a
stream.
Static Semantics
{
AI95-00270-01}
For every subtype S of an elementary type
T, the following representation
attribute is defined:
S'Stream_Size
{
AI95-00270-01}
{
AI05-0194-1}
Denotes the number of bits read from or written to a stream by the default
implementations of S'Read and S'Write. Hence, the number of stream elements
required per item of elementary type
T is:
T'Stream_Size / Ada.Streams.Stream_Element'Size
The value of this attribute is of type
universal_integer and is a multiple of Stream_Element'Size.
Stream_Size may be specified for first
subtypes via an
attribute_definition_clause;
the
expression
of such a clause shall be static, nonnegative, and a multiple of Stream_Element'Size.
Aspect Description for Stream_Size:
Size in bits used to represent elementary objects in a stream.
Discussion: Stream_Size is a type-related
attribute (see
13.1).
Ramification: {
AI05-0194-1}
The value of S'Stream_Size is unaffected by the presence or absence of
any
attribute_definition_clauses
or
aspect_specifications
specifying the Read or Write attributes of any ancestor of S. S'Stream_Size
is defined in terms of the behavior of the default implementations of
S'Read and S'Write even if those default implementations are overridden.
Implementation Advice
{
AI95-00270-01}
If not specified, the value of Stream_Size for an elementary type should
be the number of bits that corresponds to the minimum number of stream
elements required by the first subtype of the type, rounded up to the
nearest factor or multiple of the word size that is also a multiple of
the stream element size.
Implementation Advice: If not specified,
the value of Stream_Size for an elementary type should be the number
of bits that corresponds to the minimum number of stream elements required
by the first subtype of the type, rounded up to the nearest factor or
multiple of the word size that is also a multiple of the stream element
size.
Reason: {
AI95-00270-01}
This is Implementation Advice because we want to allow implementations
to remain compatible with their Ada 95 implementations, which may have
a different handling of the number of stream elements. Users can always
specify Stream_Size if they need a specific number of stream elements.
{
AI95-00270-01}
The recommended level of support for the Stream_Size
attribute is:
{
AI95-00270-01}
A Stream_Size clause should be supported for a discrete or fixed point
type
T if the specified Stream_Size is a multiple of Stream_Element'Size
and is no less than the size of the first subtype of
T, and no
greater than the size of the largest type of the same elementary class
(signed integer, modular integer, enumeration, ordinary fixed point,
or decimal fixed point).
Implementation Advice: The recommended
level of support for the Stream_Size attribute should be followed.
Ramification: There are no requirements
beyond supporting confirming Stream_Size clauses for floating point and
access types. Floating point and access types usually only have a handful
of defined formats, streaming anything else makes no sense for them.
For discrete and fixed point types, this may
require support for sizes other than the “natural” ones.
For instance, on a typical machine with 32-bit integers and a Stream_Element'Size
of 8, setting Stream_Size to 24 must be supported. This is required as
such formats can be useful for interoperability with unusual machines,
and there is no difficulty with the implementation (drop extra bits on
output, sign extend on input).
Static Semantics
For every subtype S of a specific type T,
the following attributes are defined.
S'Write
S'Write denotes a procedure with
the following specification:
{
AI95-00441-01}
procedure S'Write(
Stream :
not null access Ada.Streams.Root_Stream_Type'Class;
Item :
in T)
S'Write writes the value of Item
to Stream.
S'Read
S'Read denotes a procedure with
the following specification:
{
AI95-00441-01}
procedure S'Read(
Stream :
not null access Ada.Streams.Root_Stream_Type'Class;
Item :
out T)
S'Read reads the value of Item from
Stream.
{
8652/0040}
{
AI95-00108-01}
{
AI95-00444-01}
{
AI05-0192-1}
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.
Proof: {
AI05-0192-1}
The inheritance rules of
13.1 say that only
specified or inherited aspects are inherited; we mention it again here
as a clarification.
{
AI95-00444-01}
The default implementations of the Write and Read attributes, where available,
execute as follows:
{
8652/0040}
{
AI95-00108-01}
{
AI95-00195-01}
{
AI95-00251-01}
{
AI95-00270-01}
{
AI05-0139-2}
For elementary types, Read reads (and Write writes) the number of stream
elements implied by the Stream_Size for the type
T; the representation
of those stream elements is implementation defined. For composite types,
the Write or Read attribute for each component is called in canonical
order, which is last dimension varying fastest for an array (unless the
convention of the array is Fortran, in which case it is first dimension
varying fastest), and positional aggregate order for a record. Bounds
are not included in the stream if
T is an array type. If
T
is a discriminated type, discriminants are included only if they have
defaults. If
T is a tagged type, the tag is not included. For
type extensions, the Write or Read attribute for the parent type is called,
followed by the Write or Read attribute of each component of the extension
part, in canonical order. For a limited type extension, if the attribute
of the parent type or any progenitor type of
T is available anywhere
within the immediate scope of
T, and the attribute of the parent
type or the type of any of the extension components is not available
at the freezing point of
T, then the attribute of
T shall
be directly specified.
Implementation defined: The contents
of the stream elements read and written by the Read and Write attributes
of elementary types.
{
AI05-0023-1}
{
AI05-0264-1}
If
T is a discriminated type and its discriminants have defaults,
then S'Read first reads the discriminants from the stream without modifying
Item. S'Read then creates an object of type
T constrained
by these discriminants. The value of this object is then converted to
the subtype of
Item and is assigned to
Item. Finally, the
Read attribute for each nondiscriminant component of
Item is called
in canonical order as described above. Normal default initialization
and finalization take place for the created object.
Reason: A discriminant with a default
value is treated simply as a component of the object. On the other hand,
an array bound or a discriminant without a default value, is treated
as “descriptor” or “dope” that must be provided
in order to create the object and thus is logically separate from the
regular components. Such “descriptor” data are written by
'Output and produced as part of the delivered result by the 'Input function,
but they are not written by 'Write nor read by 'Read. A tag is like a
discriminant without a default.
{
8652/0040}
{
AI95-00108-01}
For limited type extensions, we must have a definition of 'Read and 'Write
if the parent type has one, as it is possible to make a dispatching call
through the attributes. The rule is designed to automatically do the
right thing in as many cases as possible.
{
AI95-00251-01}
Similarly, a type that has a progenitor with an available attribute must
also have that attribute, for the same reason.
{
AI05-0023-1}
The semantics of S'Read for a discriminated type with defaults involves
an anonymous object so that the point of required initialization and
finalization is well-defined, especially for objects that change shape
and have controlled components. The creation of this anonymous object
often can be omitted (see the Implementation Permissions below).
Ramification: {
AI95-00195-01}
For a composite object, the subprogram denoted by the Write or Read attribute
of each component is called, whether it is the default or is user-specified.
Implementations are allowed to optimize these calls (see below), presuming
the properties of the attributes are preserved.
{
AI95-00270-01}
{
AI05-0264-1}
Constraint_Error is raised by the predefined Write attribute if the value
of the elementary item is outside the range of values representable using
Stream_Size bits. For a signed integer type, an enumeration type, or
a fixed point type, the range is unsigned only if the integer code for
the lower bound of the first subtype is nonnegative, and a (symmetric)
signed range that covers all values of the first subtype would require
more than Stream_Size bits; otherwise, the range is signed.
For every subtype S'Class
of a class-wide type T'Class:
S'Class'Write
S'Class'Write denotes a procedure
with the following specification:
{
AI95-00441-01}
procedure S'Class'Write(
Stream :
not null access Ada.Streams.Root_Stream_Type'Class;
Item :
in T'Class)
Dispatches to the subprogram denoted by
the Write attribute of the specific type identified by the tag of Item.
S'Class'Read
S'Class'Read denotes a procedure
with the following specification:
{
AI95-00441-01}
procedure S'Class'Read(
Stream :
not null access Ada.Streams.Root_Stream_Type'Class;
Item :
out T'Class)
Dispatches to the subprogram denoted by
the Read attribute of the specific type identified by the tag of Item.
Reason: It is necessary to have class-wide
versions of Read and Write in order to avoid generic contract model violations;
in a generic, we don't necessarily know at compile time whether a given
type is specific or class-wide.
Paragraph 17 was
deleted.
Static Semantics
For every subtype S of a specific type T,
the following attributes are defined.
S'Output
S'Output denotes a procedure
with the following specification:
{
AI95-00441-01}
procedure S'Output(
Stream :
not null access Ada.Streams.Root_Stream_Type'Class;
Item :
in T)
S'Output writes the value of Item
to Stream, including any bounds or discriminants.
Ramification: Note that the bounds are
included even for an array type whose first subtype is constrained.
S'Input
S'Input denotes a function with
the following specification:
{
AI95-00441-01}
function S'Input(
Stream :
not null access Ada.Streams.Root_Stream_Type'Class)
return T
S'Input reads and returns one value from
Stream, using any bounds or discriminants written by a corresponding
S'Output to determine how much to read.
{
8652/0040}
{
AI95-00108-01}
{
AI95-00444-01}
{
AI05-0192-1}
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.
Proof: {
AI05-0192-1}
See the note following the inheritance rules for the Write attribute,
above.
{
AI95-00444-01}
The default implementations of the Output and Input attributes, where
available, execute as follows:
{
AI05-0269-1}
If
T is an array type, S'Output first writes the bounds, and S'Input
first reads the bounds. If
T has discriminants without defaults,
S'Output first writes the discriminants (using the Write attribute of
the discriminant type for each), and S'Input first reads the discriminants
(using the Read attribute of the discriminant type for each).
{
AI95-00195-01}
{
AI05-0023-1}
S'Output then calls S'Write to write the value of
Item to the
stream. S'Input then creates an object of type
T, with the bounds
or (when without defaults) the discriminants, if any, taken from the
stream, passes it to S'Read, and returns the value of the object. If
T has discriminants, then this object is unconstrained if and
only the discriminants have defaults. Normal default initialization and
finalization take place for this object (see
3.3.1,
7.6, and
7.6.1).
{
AI95-00251-01}
If
T is an abstract type, then S'Input is an abstract function.
Ramification: For an abstract type
T,
S'Input can be called in a dispatching call, or passed to an abstract
formal subprogram. But it cannot be used in nondispatching contexts,
because we don't allow objects of abstract types to exist. The designation
of this function as abstract has no impact on descendants of
T,
as
T'Input is not inherited for tagged types, but rather recreated
(and the default implementation of
T'Input calls
T'Read,
not the parent type's
T'Input). Note that
T'Input cannot
be specified in this case, as any function with the proper profile is
necessarily abstract, and specifying abstract subprograms in an
attribute_definition_clause
is illegal.
For every subtype S'Class
of a class-wide type T'Class:
S'Class'Output
S'Class'Output denotes a procedure
with the following specification:
{
AI95-00441-01}
procedure S'Class'Output(
Stream :
not null access Ada.Streams.Root_Stream_Type'Class;
Item :
in T'Class)
{
AI95-00344-01}
First writes the external tag of
Item to
Stream (by calling
String'Output(
Stream, Tags.External_Tag(
Item'Tag)) —
see
3.9) and then dispatches to the subprogram
denoted by the Output attribute of the specific type identified by the
tag. Tag_Error is raised if the tag of Item identifies a type declared
at an accessibility level deeper than that of S.
Reason: {
AI95-00344-01}
We raise Tag_Error here for nested types as such a type cannot be successfully
read with S'Class'Input, and it doesn't make sense to allow writing a
value that cannot be read.
S'Class'Input
S'Class'Input denotes a function
with the following specification:
{
AI95-00441-01}
function S'Class'Input(
Stream :
not null access Ada.Streams.Root_Stream_Type'Class)
return T'Class
{
AI95-00279-01}
{
AI95-00344-01}
{
AI05-0109-1}
First reads the external tag from
Stream and determines the corresponding
internal tag (by calling Tags.Descendant_Tag(String'Input(
Stream),
S'Tag) which might raise Tag_Error — see
3.9)
and then dispatches to the subprogram denoted by the Input attribute
of the specific type identified by the internal tag; returns that result.
If the specific type identified by the internal tag is abstract, Constraint_Error
is raised.
Ramification: {
AI05-0109-1}
Descendant_Tag will ensure that the tag it returns is covered by T'Class;
Tag_Error will be raised if it would not cover T'Class.
{
AI95-00195-01}
{
AI05-0228-1}
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.
Reason: {
AI05-0228-1}
The check for scalar components that have an implicit initial value is
to preserve our Language Design Principle that all objects that have
an implicit initial value do not become "deinitialized".
Ramification: {
AI05-0228-1}
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.
To be honest: {
AI05-0228-1}
An implementation should always be able to detect the error for a null
value read into a component of an access subtype with a null exclusion;
the "if the implementation can detect" is intended to cover
nonnull access values.
{
AI95-00195-01}
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.
{
8652/0045}
{
AI95-00132-01}
In the default implementation of Read and Input for
a type, End_Error is raised if the end of the stream is reached before
the reading of a value of the type is completed.
Reason: {
AI95-00195-01}
{
AI12-0106-1}
We need the last sentence to override the blanket rule given in
13.1.1
that aspect'Class applies to the type and all descendants.
Proof: {
AI12-0121-1}
13.1.1 says that all operational attributes
can be specified with an aspect_specification.
Aspect Description for Read'Class:
Procedure to read a value from a stream for the class-wide type associated
with a given type.
Aspect Description for Write'Class:
Procedure to write a value to a stream for a the class-wide type
associated with a given type.
Aspect Description for Input'Class:
Function to read a value from a stream for a the class-wide type
associated with a given type, including any bounds and discriminants.
Aspect Description for Output'Class:
Procedure to write a value to a stream for a the class-wide type
associated with a given type, including any bounds and discriminants.
Discussion:
{
AI95-00251-01}
Stream attributes (other than Input) are always null procedures for interface
types (they have no components). We need to allow explicit setting of
the Read and Write attributes in order that the class-wide attributes
like LI'Class'Input can be made available. (In that case, any descendant
of the interface type would require available attributes.) But we don't
allow any concrete implementation because these don't participate in
extensions (unless the interface is the parent type). If we didn't ban
concrete implementations, the order of declaration of a pair of interfaces
would become significant. For example, if Int1 and Int2 are interfaces
with concrete implementations of 'Read, then the following declarations
would have different implementations for 'Read:
type Con1 is new Int1 and Int2 with null record;
type Con2 is new Int2 and Int1 with null record;
This would violate
our design principle that the order of the specification of the interfaces
in a
derived_type_definition
doesn't matter.
Ramification:
The Input attribute cannot be specified for an interface. As it is
a function, a null procedure is impossible; a concrete function is not
possible anyway as any function returning an abstract type must be abstract.
And we don't allow specifying stream attributes to be abstract subprograms.
This has no impact, as the availability of Int'Class'Input (where Int
is a limited interface) depends on whether Int'Read (not Int'Input) is
specified. There is no reason to allow Int'Output to be specified, either,
but there is equally no reason to disallow it, so we don't have a special
rule for that.
Discussion: {
AI95-00195-01}
Limited types generally do not have default implementations of the stream-oriented
attributes. The rules defining when a stream-oriented attribute is available
(see below) determine when an attribute of a limited type is in fact
well defined and usable. The rules are designed to maximize the number
of cases in which the attributes are usable. For instance, when the language
provides a default implementation of an attribute for a limited type
based on a specified attribute for the parent type, we want to be able
to call that attribute.
Aspect Description for Read: Procedure
to read a value from a stream for a given type.
Aspect Description for Write: Procedure
to write a value to a stream for a given type.
Aspect Description for Input: Function
to read a value from a stream for a given type, including any bounds
and discriminants.
Aspect Description for Output: Procedure
to write a value to a stream for a given type, including any bounds and
discriminants.
{
AI95-00195-01}
A stream-oriented attribute for a subtype of a specific type
T
is
available at places where one of the following conditions is
true:
T is nonlimited.
The
attribute_designator
is Read (resp. Write) and
T is a limited record extension, and
the attribute Read (resp. Write) is available for the parent type of
T and for the types of all of the extension components.
Reason: In this case, the language provides
a well-defined default implementation, which we want to be able to call.
T is a limited untagged derived type, and
the attribute was inherited for the type.
Reason: Attributes are only inherited
for untagged derived types, and surely we want to be able to call inherited
attributes.
The
attribute_designator
is Input (resp. Output), and
T is a limited type, and the attribute
Read (resp. Write) is available for
T.
Reason: The default implementation of
Input and Output are based on Read and Write; so if the implementation
of Read or Write is good, so is the matching implementation of Input
or Output.
Reason: We always want to allow calling
a specified attribute. But we don't want availability to break privacy.
Therefore, only attributes whose specification can be seen count. Yes,
we defined the visibility of an
attribute_definition_clause
(see
8.3).
{
AI95-00195-01}
A stream-oriented attribute for a subtype of a class-wide type
T'Class
is available at places where one of the following conditions is true:
T is nonlimited;
the corresponding attribute of T is available,
provided that if T has a partial view, the corresponding attribute
is available at the end of the visible part where T is declared.
Reason: The rules are stricter for class-wide
attributes because (for the default implementation) we must ensure that
any specific attribute that might ever be dispatched to is available.
Because we require specification of attributes for extensions of limited
parent types with available attributes, we can in fact know this. Otherwise,
we would not be able to use default class-wide attributes with limited
types, a significant limitation.
Discussion: Stream attributes always
exist. It is illegal to call them in some cases. Having the attributes
not be defined for some limited types would seem to be a cleaner solution,
but it would lead to contract model problems for limited private types.
T'Input is available for abstract types
so that T'Class'Input is available. But we certainly don't want
to allow calls that could create an object of an abstract type. Remember
that T'Class is never abstract, so the above legality rule doesn't
apply to it. We don't have to discuss whether the attribute is specified,
as it cannot be: any function returning the type would have to be abstract,
and we do not allow specifying an attribute with an abstract subprogram.
To be honest: {
AI12-0030-1}
“These rules apply” refers to just this paragraph and not
to the rest of the rules in this section. This rule probably should have
been a Legality Rule, but the word “illegal” should key the
reader that this is a Legality Rule, no matter under what text heading
it occurs.
{
AI12-0030-1}
Unless inherited from a parent type, if any, for an untagged type having
a task, protected, or explicitly limited record part, the default implementation
of each of the Read, Write, Input, and Output attributes raises Program_Error
and performs no other action.
Discussion: {
AI12-0030-1}
It might seem that there is no need to specify the behavior of the default
implementation of a streaming attribute of, for example, a task type
because there is no way that it can be invoked. It is possible, however,
to construct an example where such a stream attribute can be invoked.
This involves using a formal untagged limited derived type for which
some streaming attribute is available (because it was explicitly specified
for the ancestor type) and a corresponding actual type for which the
attribute is unspecified (because the derivation occurred before the
aspect was specified for the ancestor type and the specification was
therefore not inherited).
{
AI95-00195-01}
{
AI05-0192-1}
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.
Discussion: {
AI05-0192-1}
An inherited stream attribute has a profile as determined by the rules
for inheriting primitive subprograms (see
13.1
and
3.4).
{
AI95-00195-01}
{
AI05-0007-1}
For an
attribute_definition_clause
specifying one of these attributes, the subtype of the
Item parameter
shall be the first subtype or the base subtype if scalar, and the first
subtype if not scalar. The same rule applies to the result of the Input
function.
Reason: This is to simplify implementation.
Ramification: The view of the type at
the point of the
attribute_definition_clause
determines whether the base subtype is allowed. Thus, for a scalar type
with a partial view (which is never scalar), whether the base subtype
is allowed is determined by whether the
attribute_definition_clause
occurs before or after the full definition of the scalar type.
{
AI95-00366-01}
{
AI05-0065-1}
[A type is said to
support
external streaming if Read and Write attributes are provided for
sending values of such a type between active partitions, with Write marshalling
the representation, and Read unmarshalling the representation.] A limited
type supports external streaming only if it has available Read and Write
attributes. A type with a part that is of a nonremote access type supports
external streaming only if that access type or the type of some part
that includes the access type component, has Read and Write attributes
that have been specified via an
attribute_definition_clause,
and that
attribute_definition_clause
is visible. [An anonymous access type does not support external streaming.
]All other types (including remote access types, see
E.2.2)
support external streaming.
Ramification: A limited type with a part
that is of a nonremote access type needs to satisfy both rules.
Erroneous Execution
{
AI95-00279-01}
{
AI95-00344-01}
If the internal tag returned by Descendant_Tag to
T'Class'Input identifies a type that is not library-level and whose tag
has not been created, or does not exist in the partition at the time
of the call, execution is erroneous.
Ramification: The definition of Descendant_Tag
prevents such a tag from being provided to T'Class'Input if T is a library-level
type. However, this rule is needed for nested tagged types.
Implementation Requirements
{
8652/0040}
{
AI95-00108-01}
For every subtype
S of a language-defined nonlimited specific
type
T, the output generated by S'Output or S'Write shall be readable
by S'Input or S'Read, respectively. This rule applies across partitions
if the implementation conforms to the Distributed Systems Annex.
{
AI95-00195-01}
{
AI05-0092-1}
If Constraint_Error is raised during a call to Read because of failure
of one the above checks, the implementation shall ensure that the discriminants
of the actual parameter of Read are not modified.
Implementation Permissions
{
AI95-00195-01}
{
AI05-0092-1}
The number of calls performed by the predefined implementation of the
stream-oriented attributes on the Read and Write operations of the stream
type is unspecified. An implementation may take advantage of this permission
to perform internal buffering. However, all the calls on the Read and
Write operations of the stream type needed to implement an explicit invocation
of a stream-oriented attribute shall take place before this invocation
returns. An explicit invocation is one appearing explicitly in the program
text, possibly through a generic instantiation (see
12.3).
{
AI05-0023-1}
{
AI05-0264-1}
If
T is a discriminated type and its discriminants have defaults,
then in two cases an execution of the default implementation of S'Read
is not required to create an anonymous object of type
T: If the
discriminant values that are read in are equal to the corresponding discriminant
values of
Item, then no object of type
T need be created
and
Item may be used instead. If they are not equal and
Item
is a constrained variable, then Constraint_Error may be raised at that
point, before any further values are read from the stream and before
the object of type
T is created.
{
AI05-0023-1}
A default implementation of S'Input that calls the default implementation
of S'Read may create a constrained anonymous object with discriminants
that match those in the stream.
Implementation
Note: This allows the combined executions of S'Input and S'Read to
create one object of type T instead of two. If this option is
exercised, then:
The discriminants are read from the stream
by S'Input, not S'Read.
S'Input declares an object of type T
constrained by the discriminants read from the stream, not an unconstrained
object.
The discriminant values that S'Read would
normally have read from the stream are read from Item instead.
The permissions of the preceding paragraph
then apply and no object of type T need be created by the execution
of S'Read.
40 For a definite subtype S of a type T,
only T'Write and T'Read are needed to pass an arbitrary
value of the subtype through a stream. For an indefinite subtype S of
a type T, T'Output and T'Input will normally be
needed, since T'Write and T'Read do not pass bounds, discriminants,
or tags.
41 User-specified attributes of S'Class
are not inherited by other class-wide types descended from S.
Examples
Example of user-defined
Write attribute:
{
AI95-00441-01}
procedure My_Write(
Stream :
not null access Ada.Streams.Root_Stream_Type'Class;
Item : My_Integer'Base);
for My_Integer'Write
use My_Write;
Discussion:
Example of network input/output using input output attributes:
with Ada.Streams; use Ada.Streams;
generic
type Msg_Type(<>) is private;
package Network_IO is
-- Connect/Disconnect are used to establish the stream
procedure Connect(...);
procedure Disconnect(...);
-- Send/Receive transfer messages across the network
procedure Send(X : in Msg_Type);
function Receive return Msg_Type;
private
type Network_Stream is new Root_Stream_Type with ...
procedure Read(...); -- define Read/Write for Network_Stream
procedure Write(...);
end Network_IO;
with Ada.Streams; use Ada.Streams;
package body Network_IO is
Current_Stream : aliased Network_Stream;
. . .
procedure Connect(...) is ...;
procedure Disconnect(...) is ...;
procedure Send(X : in Msg_Type) is
begin
Msg_Type'Output(Current_Stream'Access, X);
end Send;
function Receive return Msg_Type is
begin
return Msg_Type'Input(Current_Stream'Access);
end Receive;
end Network_IO;
Inconsistencies With Ada 95
{
8652/0040}
{
AI95-00108-01}
Corrigendum: Clarified how the default implementation
for stream attributes is determined (eliminating conflicting language).
The new wording provides that attributes for type extensions are created
by composing the parent's attribute with those for the extension components
if any. If a program was written assuming that the extension components
were not included in the stream (as in original Ada 95), it would fail
to work in the language as corrected by the Corrigendum.
{
AI95-00195-01}
Amendment Correction: Explicitly provided a permission that the
number of calls to the underlying stream Read and Write operations may
differ from the number determined by the canonical operations. If Ada
95 code somehow depended on the number of calls to Read or Write, it
could fail with an Ada 2005 implementation. Such code is likely to be
very rare; moreover, such code is really wrong, as the permission applies
to Ada 95 as well.
Extensions to Ada 95
{
AI95-00270-01}
The Stream_Size attribute is new. It allows specifying
the number of bits that will be streamed for a type. The Implementation
Advice involving this also was changed; this is not incompatible because
Implementation Advice does not have to be followed.
{
8652/0040}
{
AI95-00108-01}
{
AI95-00195-01}
{
AI95-00444-01}
Corrigendum: Limited types may have default constructed attributes
if all of the parent and (for extensions) extension components have available
attributes. Ada 2005 adds the notion of availability to patch up some
holes in the Corrigendum model.
Wording Changes from Ada 95
{
8652/0045}
{
AI95-00132-01}
Corrigendum: Clarified that End_Error is raised by the default
implementation of Read and Input if the end of the stream is reached.
(The result could have been abnormal without this clarification, thus
this is not an inconsistency, as the programmer could not have depended
on the previous behavior.)
{
AI95-00195-01}
Clarified that the default implementation of S'Input does normal initialization
on the object that it passes to S'Read.
{
AI95-00195-01}
Explicitly stated that what is read from a stream when a required check
fails is unspecified.
{
AI95-00251-01}
Defined availability and default implementations for types with progenitors.
{
AI95-00279-01}
Specified that Constraint_Error is raised if the internal tag retrieved
for S'Class'Input is for some type not covered by S'Class or is abstract.
We also explicitly state that the program is erroneous if the tag has
not been created or does not currently exist in the partition. (Ada 95
did not specify what happened in these cases; it's very unlikely to have
provided some useful result, so this is not considered an inconsistency.)
{
AI95-00344-01}
Added wording to support nested type extensions. S'Input and S'Output
always raise Tag_Error for such extensions, and such extensions were
not permitted in Ada 95, so this is neither an extension nor an incompatibility.
{
AI95-00366-01}
Defined
supports external streaming to put all of the rules about
“good” stream attributes in one place. This is used for distribution
and for defining pragma Pure.
{
AI95-00441-01}
Added the
not null qualifier to the first parameter of all of
the stream attributes, so that the semantics doesn't change between Ada
95 and Ada 2005. This change is compatible, because mode conformance
is required for subprograms specified as stream attributes, and
null_exclusions
are not considered for mode conformance.
{
AI95-00444-01}
Improved the wording to make it clear that we don't define the default
implementations of attributes that cannot be called (that is, aren't
“available”). Also clarified when inheritance takes place.
Incompatibilities With Ada 2005
{
AI05-0039-1}
Correction: Added a requirement that stream
attributes be specified by a static subprogram name rather than a dynamic
expression. Expressions cannot provide any useful functionality because
of the freezing rules, and the possibility of them complicates implementations.
Only pathological programs should be affected.
Extensions to Ada 2005
{
AI05-0007-1}
Correction: Stream attributes for scalar types
can be specified with subprograms that take the first subtype as well
as the base type. This eliminates confusion about which subtype is appropriate
for attributes specified for partial views whose full type is a scalar
type. It also eliminates a common user error (forgetting 'Base).
Wording Changes from Ada 2005
{
AI05-0023-1}
Correction: Corrected the definition of the default version S'Read
and S'Input to be well-defined if S is a discriminated type with defaulted
discriminants and some components require initialization and/or finalizations.
{
AI05-0065-1}
Correction: Defined remote access types to support external streaming,
since that is their purpose.
{
AI05-0109-1}
Correction: Removed a misleading phrase which implies that Constraint_Error
is raised for internal tags of the wrong type, when Tag_Error should
be raised for such tags.
{
AI05-0139-2}
Clarified that arrays with convention Fortran are written in column-major
order, rather then row-major order. This is necessary in order that streaming
of Fortran arrays is efficient.
{
AI05-0192-1}
Correction: Clarified that the profile of an inherited stream
attribute is as defined for an inherited primitive subprogram, while
the default implementation of the same attribute might have a different
profile.
{
AI05-0194-1}
Correction: Clarified that Stream_Size has no effect on and is
not effected by user-defined stream attributes.
Extensions to Ada 2012
{
AI12-0106-1}
Corrigendum: Defined how to specify a class-wide
stream-oriented attribute using an
aspect_specification.
It was always intended that this was possible, but the method was not
clear, as a class-wide type never has an explicit declaration.
Wording Changes from Ada 2012
{
AI12-0030-1}
Corrigendum: Defined the runtime effect of stream attributes for
untagged limited types, as there is a weird corner case where they can
be called. We don't specify this as an inconsistency, as it doesn't make
semantic sense to stream a task, and nothing useful could have been done
with that, so it should not exist in any programs.
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe