[Home] [Prev] [Next] [Index]

13.13 Streams

13.13 Streams

1
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.

1.a
Discussion:  A stream element will often be the same size as a storage element, but that is not required.

Extensions to Ada 83

1.b
Streams are new in Ada 9X.

13.13.1 The Package Streams

Static Semantics

1
The 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.)

2
package Ada.Streams is
    pragma Pure(Streams);

3
    type Root_Stream_Type is abstract tagged limited private;

4
    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 Stream_Element;

5
    procedure Read(
      Stream : in out Root_Stream_Type;
      Item   : out Stream_Element_Array;
      Last   : out Stream_Element_Offset) is abstract;

6
    procedure Write(
      Stream : in out Root_Stream_Type;
      Item   : in Stream_Element_Array) is abstract;

7
private
   ... -- not specified by the language
end Ada.Streams;

8
The Read operation transfers Item'Length stream elements from the specified stream to fill the array Item.  The index of the last stream element transferred is returned in Last.  Last is less than Item'Last only if the end of the stream is reached.

9
The Write operation appends Item to the specified stream.

NOTES

10 30
See A.12.1, "The Package Streams.Stream_IO" for an example of extending type Root_Stream_Type.

13.13.2 Stream-Oriented Attributes

1
The 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.

9
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. 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.

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.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
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
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 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).

36
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. 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.

NOTES

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;



[Home] [Prev] [Next] [Index]

documentation@rational.com
Copyright © 1993-1998, Rational Software Corporation.   All rights reserved.