[m-rev.] for review: stream typeclasses

Peter Ross pro at missioncriticalit.com
Mon Oct 23 17:33:06 AEST 2006


On Mon, Oct 23, 2006 at 04:38:36PM +1000, Julien Fischer wrote:
> Estimated hours taken: 30 (+ unknown by Ian) (+ unknown late last year)
> Branches: main
> 
> Add a new module to the standard library that provides generic stream
> handling via a family of typeclasses.  This subsumes the functionality
> provided by the existing stream library in extras and improves upon that
> design in several ways.
> 
> This incarnation of streams is parameterized over the state that is
> updated by the stream operations, i.e. it is no longer restricted to
> just being the I/O state**.  Streams are also parameterized over the
> type of the data being written to, or read from, them.  This allows for
> efficient implementations of operations like write_string, and also
> allows the put and get methods for a single stream to be overloaded.
> 
> Subsequent diffs will extend the io module to make the standard file
> streams instances of these typeclasses and convert things like the
> pretty printer and term_to_xml to use them as well.
> 
> ** Limitations in the current implementation of typeclasses currently
>    make this less useful than it might initially appear.
> 
What limitations?

> Index: library/stream.m
> ===================================================================
> RCS file: library/stream.m
> diff -N library/stream.m
> --- /dev/null	1 Jan 1970 00:00:00 -0000
> +++ library/stream.m	23 Oct 2006 04:59:46 -0000
> @@ -0,0 +1,353 @@

[snip]

> +%-----------------------------------------------------------------------------%
> +%
> +% Input streams
> +%
> +
> +    % An input stream is a source of data.
> +    %
> +:- typeclass stream.input(Stream, State, Error)
> +    <= ( stream(Stream, State), stream.error(Error), (Stream -> Error) )
> +    where
> +[
> +    % For buffered input streams this method causes the buffer
> +    % to be filled.  For unbuffered streams it is a no-op.
> +    %
> +    pred fill(Stream::in, State::di, State::uo) is det
> +].
> +
Why do you need a fill predicate?

If streams are managing there own buffer, I can't see how it can be to
the users benefit to request the buffer to be filled, unless the filling
of the buffer is an asynchronous operation.

If the stream doesn't manage it's own buffer, then shouldn't one
have an is_input_buffer_empty predicate?

Anyway more justification of this is needed for me.

> +    % A reader stream is a subclass of specific input stream that can be
> +    % used to read data of a specific type from the input stream. 
> +    % A single input streams can support multiple reader subclasses.
> +    % 
> +:- typeclass stream.reader(Stream, Unit, State, Error)
> +    <= stream.input(Stream, State, Error) where
> +[
> +    % Get the next unit from the given stream.
> +    % The get operation should block until the next unit is available.
> +    %
> +    pred get(Stream::in, stream.result(Unit, Error)::out,
> +        State::di, State::uo) is det
> +].
> +
I think streams should support non-blocking I/O as well.
I can't forsee any problems due to the current hierachy of typeclasses
to supporting non-blocking I/O, but I haven't thought about it deeply.
Have you?

> +%-----------------------------------------------------------------------------%
> +%
> +% Output streams
> +%
> + 
> +    % An output stream is a destination for data.
> +    % Note that unlike input streams, output stream do not include
> +    % an explicit error type.  They should handle errors by throwing
> +    % a exceptions.
> +    %

s/a //g

> +:- typeclass stream.output(Stream, State)
> +    <= stream(Stream, State) where
> +[
> +    % For buffered output streams completely write out any data in the
> +    % buffer.  For unbuffered streams this operation is a no-op.
> +    %
> +    pred flush(Stream::in, State::di, State::uo) is det
> +].
> +
> +    % A writer stream is a subclass of specific output stream that can be
> +    % used to write data of a specific type to the output stream. 
> +    % A single output stream can support multiple writer subclasses.
> +    %
> +:- typeclass stream.writer(Stream, Unit, State)
> +    <= stream.output(Stream, State) where
> +[
> +    % Write the next unit to the given stream.
> +    % The put operation should block until the unit is completely written.
> +    %
> +    pred put(Stream::in, Unit::in, State::di, State::uo) is det
> +].
> +
> +%-----------------------------------------------------------------------------%
> +%
> +% Duplex streams
> +%
> +
> +    % A duplex stream is a stream that can act as both a source
> +    % and destination of data, i.e. it is a both an input and
> +    % an output stream.
> +    %
> +:- typeclass stream.duplex(Stream, State, Error)
> +    <= ( stream.input(Stream, State, Error), stream.output(Stream, State))
> +        where [].
> +
> +%----------------------------------------------------------------------------%
> +%
> +% Putback streams
> +%
> +
> +    % A putback stream is an input stream that allows data to be
> +    % pushed back onto the stream.  As with reader subclasses it is
> +    % possible to define multiple putback subclasses for a
> +    % single input stream.
> +    %
> +:- typeclass stream.putback(Stream, Unit, State, Error)
> +    <= stream.reader(Stream, Unit, State, Error) where
> +[
> +    % Un-gets a unit from the specified input stream.
> +    % At least one unit of can be placed back on the stream.
> +    %
> +    pred unget(Stream::in, Unit::in, State::di, State::uo) is det
> +]. 

I would reword that to say only one unit of putback is guaranteed to be
successful.

> + 
> +    % As above but guarantees that an unlimited number of units may
> +    % be pushed back onto the stream.
> +    %
> +:- typeclass stream.unbounded_putback(Stream, Unit, State, Error)
> +    <= stream.putback(Stream, Unit, State, Error) where [].
> +

[snip]

The only issue that I can think of is to do with the issue that you have
a di/uo state pair.  Does this mean that there is going to be a problem
with nested uniqueness?

For a concrete example, an encrypt/decrypt stream which is layered on
top of another stream.

Apart from that it looks great.
--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to:       mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions:          mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------



More information about the reviews mailing list