Contents Index Search Previous Next
13.13.2 Stream-Oriented Attributes
1/1
{
8652/0009}
The
operational attributes Write, Read, Output, and Input
attributes
convert values to a stream of elements and reconstruct values from
a stream.
Static Semantics
2
For every subtype S of a specific type T,
the following attributes are defined.
3
- S'Write
-
S'Write denotes a procedure with
the following specification:
4
procedure S'Write(
Stream : access Ada.Streams.Root_Stream_Type'Class;
Item : in T)
5
- S'Write writes the value of
Item to Stream.
6
- S'Read
-
S'Read denotes a procedure with
the following specification:
7
procedure S'Read(
Stream : access Ada.Streams.Root_Stream_Type'Class;
Item : out T)
8
- S'Read reads the value of Item
from Stream.
8.1/1
{
8652/0040}
For untagged derived types, the Write and Read attributes of the parent
type are inherited as specified in 13.1; otherwise,
the default implementations of these attributes are used. The default
implementations of Write and Read attributes execute as follows:
9/1
{
8652/0040}
For elementary types, the representation in terms of stream elements
is implementation defined. For composite types, the Write or Read attribute
for each component is called in
a canonical order
, which .
The canonical order of components is last dimension varying fastest
for an array, 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 any ancestor type of T has been directly specified and the
attribute of any ancestor type of the type of any of the extension components
which are of a limited type has not been specified, the attribute of
T shall be directly specified.
9.a
Implementation defined: The
representation used by the Read and Write attributes of elementary types
in terms of stream elements.
9.b
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.
9.b.1/1
{8652/0040}
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.
9.c
Ramification: 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.
10
For every subtype
S'Class of a class-wide type T'Class:
11
- S'Class'Write
-
S'Class'Write denotes a procedure
with the following specification:
12
procedure S'Class'Write(
Stream : access Ada.Streams.Root_Stream_Type'Class;
Item : in T'Class)
13
- Dispatches to the subprogram
denoted by the Write attribute of the specific type identified by the
tag of Item.
14
- S'Class'Read
-
S'Class'Read denotes a procedure
with the following specification:
15
procedure S'Class'Read(
Stream : access Ada.Streams.Root_Stream_Type'Class;
Item : out T'Class)
16
- Dispatches to the subprogram
denoted by the Read attribute of the specific type identified by the
tag of Item.
16.a
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.
Implementation Advice
17
If a stream element is the same size as a storage
element, then the normal in-memory representation should be used by Read
and Write for scalar objects. Otherwise, Read and Write should use the
smallest number of stream elements needed to represent all values in
the base range of the scalar type.
Static Semantics
18
For every subtype S of a specific type T,
the following attributes are defined.
19
- S'Output
-
S'Output denotes a procedure
with the following specification:
20
procedure S'Output(
Stream : access Ada.Streams.Root_Stream_Type'Class;
Item : in T)
21
- S'Output writes the value of
Item to Stream, including any bounds or discriminants.
21.a
Ramification: Note that
the bounds are included even for an array type whose first subtype is
constrained.
22
- S'Input
-
S'Input denotes a function with
the following specification:
23
function S'Input(
Stream : access Ada.Streams.Root_Stream_Type'Class)
return T
24
- 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.
25/1
{
8652/0040}
For untagged derived types, the Output and Input attributes of the
parent type are inherited as specified in 13.1;
otherwise, the default implementations of these attributes are used.
The default implementations of Output and Input attributes execute as
follows: Unless overridden by an attribute_definition_clause,
these subprograms execute as follows:
26
- 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 S'Write for each), and S'Input
first reads the discriminants (using S'Read for each).
27
- S'Output then calls S'Write to write
the value of Item to the stream. S'Input then 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.
28
For every subtype
S'Class of a class-wide type T'Class:
29
- S'Class'Output
-
S'Class'Output denotes a procedure
with the following specification:
30
procedure S'Class'Output(
Stream : access Ada.Streams.Root_Stream_Type'Class;
Item : in T'Class)
31
- First writes the external tag
of Item to Stream (by calling String'Output(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.
32
- S'Class'Input
-
S'Class'Input denotes a function
with the following specification:
33
function S'Class'Input(
Stream : access Ada.Streams.Root_Stream_Type'Class)
return T'Class
34
- First reads the external tag
from Stream and determines the corresponding internal tag (by
calling Tags.Internal_Tag(String'Input(Stream)) -- 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.
35
{Range_Check [partial]}
{check, language-defined (Range_Check)}
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 (raised by failure of run-time
check)} 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).
35.1/1
{
8652/0045}
{End_Error (raised by failure of run-time check)}
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.
36/1
{
8652/0040}
{specifiable (of Read for a type) [partial]}
{specifiable (of Write for a type)
[partial]} {specifiable
(of Input for a type) [partial]} {specifiable
(of Output for a type) [partial]} {Read
clause} {Write clause}
{Input clause} {Output
clause} The stream-oriented attributes
may be specified for any type via an
attribute_definition_clause.
All nonlimited types have default implementations for these operations.
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
or [(for a type extension)] the attribute has been specified for an ancestor
type . For an
attribute_definition_clause
specifying one of these attributes, the subtype of the Item parameter
shall be the base subtype if scalar, and the first subtype otherwise.
The same rule applies to the result of the Input function.
36.a
Reason: This is to simplify
implementation.
36.a.1/1
Discussion: {8652/0040}
``Specified'' includes inherited attributes, and default implementations
are never inherited. So, for untagged limited types, the second part
of the attribute_reference rule
has the same meaning as the first part. However, tagged types never inherit
attributes, so the second rule is needed so that the default implementations
for the attributes can be called when those are constructed from a directly
specified ancestor.
Implementation Requirements
36.1/1
{
8652/0040}
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.
37
31 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.
38
32 User-specified attributes
of S'Class are not inherited by other class-wide types descended from
S.
Examples
39
Example of user-defined
Write attribute:
40
procedure My_Write(
Stream : access Ada.Streams.Root_Stream_Type'Class; Item : My_Integer'Base);
for My_Integer'Write use My_Write;
40.a
Discussion:
Example of network input/output using input output attributes:
40.b
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(...);
40.c
-- 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;
40.d
with Ada.Streams; use Ada.Streams;
package body Network_IO is
Current_Stream : aliased Network_Stream;
. . .
procedure Connect(...) is ...;
procedure Disconnect(...) is ...;
40.e
procedure Send(X : in Msg_Type) is
begin
Msg_Type'Output(Current_Stream'Access, X);
end Send;
40.f
function Receive return Msg_Type is
begin
return Msg_Type'Input(Current_Stream'Access);
end Receive;
end Network_IO;
Contents Index Search Previous Next Legal