13.13 Streams
This Reference Manual output has not been verified, and may contain omissions or errors. Report any problems on the tracking issue
A stream is a sequence of elements comprising values from possibly different types and allowing sequential access to these values. A stream type is a type in the class whose root type is Streams.Root_Stream_Type. A stream type may be implemented in various ways, such as an external sequential file, an internal buffer, or a network channel.
Extensions to Ada 83
13.13.1 The Streams Subsystem
Static Semantics
1The abstract type Root_Stream_Type is the root type of the class of stream types. The types in this class represent different kinds of streams. A new stream type is defined by extending the root type (or some other stream type), overriding the Read and Write operations, and optionally defining additional primitive subprograms, according to the requirements of the particular kind of stream. The predefined stream-oriented attributes like T'Read and T'Write make dispatching calls on the Read and Write procedures of the Root_Stream_Type. (User-defined T'Read and T'Write attributes can also make such calls, or can call the Read and Write attributes of other types.)
The library package Ada.Streams has the following declaration:
package Ada.Streams
with Pure, Nonblocking => False is
3/2type Root_Stream_Type is abstract tagged limited private
with Preelaborable_Initialization ;
4/1{8652/0044} type Stream_Element is mod implementation-defined;
type Stream_Element_Offset is range implementation-defined;
subtype Stream_Element_Count is
Stream_Element_Offset range 0..Stream_Element_Offset'Last;
type Stream_Element_Array is
array(Stream_Element_Offset range <>) of aliased Stream_Element;
5procedure Read(
Stream : in out Root_Stream_Type;
Item : out Stream_Element_Array;
Last : out Stream_Element_Offset) is abstract;
6procedure Write(
Stream : in out Root_Stream_Type;
Item : in Stream_Element_Array) is abstract;
7private
... -- not specified by the language
end Ada.Streams;
The Read operation transfers stream elements from the specified stream to fill the array Item. Elements are transferred until Item'Length elements have been transferred, or until the end of the stream is reached. If any elements are transferred, the index of the last stream element transferred is returned in Last. Otherwise, Item'First - 1 is returned in Last. Last is less than Item'Last only if the end of the stream is reached.
The Write operation appends Item to the specified stream.
Three additional packages provide stream implementations that do not make use of any file operations. These packages provide the same operations, with Streams.Storage providing an abstract interface, and two child packages providing implementations of that interface. The difference is that for Streams.Storage.Bounded, the maximum storage is bounded.
The library package Ada.Streams.Storage has the following declaration:
package Ada.Streams.Storage
with Pure, Nonblocking is
13/5type Storage_Stream_Type is abstract new Root_Stream_Type with private;
14/5function Element_Count (Stream : Storage_Stream_Type)
return Stream_Element_Count is abstract;
15/5procedure Clear (Stream : in out Storage_Stream_Type) is abstract;
16/5private
... -- not specified by the language
end Ada.Streams.Storage;
17/5The library package Ada.Streams.Storage.Unbounded has the following declaration:
package Ada.Streams.Storage.Unbounded
with Prelaborated, Nonblocking, Global => in out synchronized is
19/5type Stream_Type is new Storage_Stream_Type with private
with Default_Initial_Condition =>
Element_Count (Stream_Type) = 0;
20/5overriding
procedure Read (
Stream : in out Stream_Type;
Item : out Stream_Element_Array;
Last : out Stream_Element_Offset)
with Post =>
(declare
Num_Read : constant Stream_Element_Count :=
Stream_Element_Count'Min
(Element_Count(Stream)'Old, Item'Length);
begin
Last = Num_Read + Item'First - 1 and
Element_Count (Stream) =
Element_Count (Stream)'Old - Num_Read);
overriding
procedure Write (
Stream : in out Stream_Type;
Item : in Stream_Element_Array)
with Post =>
Element_Count (Stream) =
Element_Count (Stream)'Old + Item'Length;
22/5overriding
function Element_Count (Stream : Stream_Type)
return Stream_Element_Count;
23/5overriding
procedure Clear (Stream : in out Stream_Type)
with Post => Element_Count (Stream) = 0;
24/5private
... -- not specified by the language
end Ada.Streams.Storage.Unbounded;
25/5The library package Ada.Streams.Storage.Bounded has the following declaration:
package Ada.Streams.Storage.Bounded
with Pure, Nonblocking is
27/5type Stream_Type (Max_Elements : Stream_Element_Count)
is new Storage_Stream_Type with private
with Default_Initial_Condition =>
Element_Count (Stream_Type) = 0;
28/5overriding
procedure Read (
Stream : in out Stream_Type;
Item : out Stream_Element_Array;
Last : out Stream_Element_Offset)
with Post =>
(declare
Num_Read : constant Stream_Element_Count :=
Stream_Element_Count'Min
(Element_Count(Stream)'Old, Item'Length);
begin
Last = Num_Read + Item'First - 1 and
Element_Count (Stream) =
Element_Count (Stream)'Old - Num_Read);
29/5overriding
procedure Write (
Stream : in out Stream_Type;
Item : in Stream_Element_Array)
with Pre =>
Element_Count (Stream) + Item'Length <= Stream.Max_Elements
or else (raise Constraint_Error),
Post =>
Element_Count (Stream) =
Element_Count (Stream)'Old + Item'Length;
30/5overriding
function Element_Count (Stream : Stream_Type)
return Stream_Element_Count
with Post => Element_Count'Result <= Stream.Max_Elements;
31/5overriding
procedure Clear (Stream : in out Stream_Type)
with Post => Element_Count (Stream) = 0;
32/5private
... -- not specified by the language
end Ada.Streams.Storage.Bounded;
33/5The Element_Count functions return the number of stream elements that are available for reading from the given stream.
The Read and Write procedures behave as described for package Ada.Streams above. Stream elements are read in FIFO (first-in, first-out) order; stream elements are available for reading immediately after they are written.
The Clear procedures remove any available stream elements from the given stream.
Implementation Permissions
36/5{8652/0044} If Stream_Element'Size is not a multiple of System.Storage_Unit, then the components of Stream_Element_Array will not be aliased.
Implementation Advice
37/5Streams.Storage.Bounded.Stream_Type objects should be implemented without implicit pointers or dynamic allocation.
Extensions to Ada 95
Wording Changes from Ada 95
Extensions to Ada 2012
13.13.2 Stream-Oriented Attributes
1/3{8652/0009} 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
1.1/2For every subtype S of an elementary type T, the following representation attribute is defined:
S'Stream_Size
- 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
; theexpression
of such a clause shall be static, nonnegative, and a multiple of Stream_Element'Size.
attribute_definition_clause
s or aspect_specification
s 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
1.6/2If 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.
The recommended level of support for the Stream_Size attribute is:
- 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).
Static Semantics
2For every subtype S of a specific type T, the following attributes are defined.
S'Write
- S'Write denotes a procedure with the following specification:
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:
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.
This paragraph was deleted.{8652/0040}
The default implementations of the Write and Read attributes, where available, execute as follows:
{8652/0040} For nonderived 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 nonderived composite types, the Write or Read attribute for each component (excluding those, if any, that are not components of the nominal type of the object) 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. For untagged derived types, the Write (resp. Read) attribute invokes the corresponding attribute of the parent type, if the attribute is available for the parent type.
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.
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:
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:
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.
Paragraph 17 was deleted.
Static Semantics
18For every subtype S of a specific type T, the following attributes are defined.
S'Output
- S'Output denotes a procedure with the following specification:
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.
S'Input
- S'Input denotes a function with the following specification:
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} For an untagged derived type, the default implementation of the Output (resp. Input) attribute invokes the corresponding attribute of the parent type, if the attribute is available for the parent type . For any other type, the default implementations of the Output and Input attributes, where available, execute as follows:
- 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).
- 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).
If T is an abstract type, then S'Input is an abstract function.
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:
procedure S'Class'Output(
Stream : not null access Ada.Streams.Root_Stream_Type'Class;
Item : in T'Class)
- 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.
S'Class'Input
- S'Class'Input denotes a function with the following specification:
function S'Class'Input(
Stream : not null access Ada.Streams.Root_Stream_Type'Class)
return T'Class
- First reads the external tag from Stream and determines the corresponding internal tag (by calling Tags.Descendant_Tag(String'Input(Stream), S'Tag) which can 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.
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.
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} 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.
The Nonblocking aspect is statically True and the Global aspect is null for the default implementations of stream-oriented attributes for elementary types. For the default implementations of stream-oriented attributes for composite types, the value of the Nonblocking aspect is that of the first subtype, and the Global aspect defaults to that of the first subtype. A default implementation of a stream-oriented attribute that has the Nonblocking aspect statically True is considered a nonblocking region. The aspect Dispatching (see H.7.1) is Read(Stream) for the default implementations of the stream-oriented attributes Read, Read'Class, Input, and Input'Class; the aspect Dispatching is Write(Stream) for the default implementations of the stream-oriented attributes Write, Write'Class, Output, and Output'Class.
{8652/0040} The stream-oriented attributes may be specified for any type via an attribute_definition_clause
. [Alternatively, each of the specific stream-oriented attributes may be specified using an aspect_specification
on any type_declaration
, with the aspect name being the corresponding attribute name.] Each of the class-wide stream-oriented attributes may be specified using an aspect_specification
for a tagged type T using the name of the stream-oriented attribute followed by 'Class; such class-wide aspects do not apply to other descendants of T. If not directly specified, a default implementation of a stream-oriented attribute is implicitly composed for a nonlimited type, and for certain limited types, as defined above.
The subprogram name given in such an attribute_definition_clause
or aspect_specification
shall statically denote a subprogram that is not an abstract subprogram. Furthermore, if a specific stream-oriented attribute is specified for an interface type, the subprogram name given in the attribute_definition_clause
or aspect_specification
shall statically denote a null procedure.
type Con1 is new Int1 and Int2 with null record;
type Con2 is new Int2 and Int1 with null record;
derived_type_definition
doesn't matter. 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.
- T is a limited untagged derived type, and the attribute is available for the parent type.
- The
attribute_designator
is Input (resp. Output), and T is a limited type, and the attribute Read (resp. Write) is available for T.
- The attribute has been specified via an
attribute_definition_clause
oraspect_specification
, and theattribute_definition_clause
oraspect_specification
is visible.
attribute_definition_clause
(see 8.3). 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 attribute has been specified via an
attribute_definition_clause
oraspect_specification
, and theattribute_definition_clause
oraspect_specification
is visible; or 48/2 - 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.
An attribute_reference
for one of the stream-oriented attributes is illegal unless the attribute is available at the place of the attribute_reference
. Furthermore, an attribute_reference
for T'Input is illegal if T is an abstract type. In addition to the places where Legality Rules normally apply (see 12.3), these rules also apply in the private part of an instance of a generic unit.
Unless available for 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.
In the parameter_and_result_profile
s 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.
For an attribute_definition_clause
or aspect_specification
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.
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. For the same reason, the base subtype is never allowed for an attribute specified via an aspect_specification
on the partial view. [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.
Erroneous Execution
53/2If 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.
Implementation Requirements
54/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.
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
56/5The 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 used 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).
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 creation of a new object of type T may be bypassed 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.
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.
- 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.
Examples
59Example of user-defined Write attribute:
procedure My_Write(
Stream : not null access Ada.Streams.Root_Stream_Type'Class;
Item : My_Integer'Base);
for My_Integer'Write use My_Write;
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(...);
60.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;
60.dwith Ada.Streams; use Ada.Streams;
package body Network_IO is
Current_Stream : aliased Network_Stream;
. . .
procedure Connect(...) is ...;
procedure Disconnect(...) is ...;
60.eprocedure Send(X : in Msg_Type) is
begin
Msg_Type'Output(Current_Stream'Access, X);
end Send;
60.ffunction Receive return Msg_Type is
begin
return Msg_Type'Input(Current_Stream'Access);
end Receive;
end Network_IO;
Inconsistencies With Ada 95
Extensions to Ada 95
Wording Changes from Ada 95
null_exclusion
s are not considered for mode conformance.Incompatibilities With Ada 2005
Extensions to Ada 2005
Wording Changes from Ada 2005
Inconsistencies With Ada 2012
Extensions to Ada 2012
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
aspect_specification
as applied when it is specified via an attribute_definition_clause
.