[m-dev.] for discussion: stream library v2

Peter Ross peter.ross at miscrit.be
Mon Sep 25 22:27:31 AEDT 2000


On Mon, Sep 25, 2000 at 10:49:03AM +1100, Fergus Henderson wrote:
> On 24-Sep-2000, Peter Ross <petdr at miscrit.be> wrote:
> > Please find attached my second attempt at a stream library.  This time
> > I have tried to define a typeclass for an impure lowlevel interface
> > for streams, and then defined a pure interface on top of that.
> 
> I think it's a good idea to build streams using a lowlevel interface
> for defining streams with a highlevel interface for using streams
> built on top of that, but it would be nicer if the lowlevel interface
> didn't need to be impure.
> 
I think that the low level interface has to be impure, that is why it is
lowlevel.

> > PS. I also attached the socket implementation which uses this new
> > interface.
> 
> It would also be a good idea to have an implementation of ordinary file
> I/O using this new interface.
> 
Yes I have done one but I haven't really tested it yet while I have used
the socket interface quite a bit, plus I didn't want to do to much
implementation work until the interface had settled down into its final
shape.

> > Any comments?
> > And should I place this stuff into the std library?
> 
> Not yet, IMHO -- see the comments below.
> 
> > :- module stream.
> > 

[snip]

> 
> > :- type stream(S) ---> stream(list(char)).
> 
> You should document what the list(char) represents,
> and why the `S' parameter is not used.
> 
The more I think about it the more I am convinced that this type should
change to

:- type stream(S)
    --->    stream(
                S,              % Handle on the stream
                list(char)      % putback characters
            ).

which means that we no longer have to pass the handle around, for
example stream__write_char becomes

:- pred stream__write_char(char::in, stream(S)::di, stream(S)::uo) is det.

> > :- pragma promise_pure(stream__read_char/4).
> > stream__read_char(Stream, Result, stream(PutbackChars), StreamOut) :-
> > 	(
> > 		PutbackChars = [],
> > 		NewPutbackChars = PutbackChars,
> > 		( impure lowlevel__read_char(Stream, Chr) ->
> > 			Result = ok(Chr)
> > 		;
> > 			( semipure lowlevel__eof(Stream) ->
> > 				Result = eof
> > 			;
> > 				semipure Err = lowlevel__error_message(Stream),
> > 				Result = error(Err)
> > 			)
> > 		)
> > 	;
> > 		PutbackChars = [Chr | NewPutbackChars],
> > 		Result = ok(Chr)
> > 	),
> > 	unsafe_promise_unique(stream(NewPutbackChars), StreamOut).
> 
> Here you're assuming that if the stream is at eof, then the
> previous operation succeeded.  This assumption is not documented
> in the lowlevel interface, and I don't think it is likely to hold in
> general.  Making this assumption may cause some errors to be ignored.
> 
You are correct that the assumption needs to be documented.

I arrived at this interface because fgetc return EOF on error or end of
file.  So first I check to see whether I am at EOF and if not it must be
an error.

> Also, why do you need `unsafe_promise_unique' here?
> 
I don't it is an artifact from my first implementation.

> > stream__putback_char(_Stream, Chr, stream(PutbackChars), StreamOut) :-
> > 	unsafe_promise_unique(stream([Chr | PutbackChars]), StreamOut).
> 
> Rather than calling unsafe_promise_unique here, it would be nicer to call
> copy/2 on Chr. 
> 
> Currently copy/2 is not as efficient as it could be, so for efficiency
> you might want to define
> 
> 	:- func copy_char(char::in) = (char::ui).
> 	copy_char(C0) = C :-
> 		unsafe_promise_unique(C0, C).
> 
> and use that instead.  But this is still an improvement, because calling
> unsafe_promise_unique on a char is nicer than calling it on a stream,
> since it's easier for a reader to understand why it is safe.
> 
Yes I agree wholeheartedly.

> > :- pragma promise_pure(stream__write_char/4).
> > stream__write_char(Stream, Chr, StreamIn, StreamOut) :-
> > 		% XXX A better design choice may be to throw the
> > 		% stream_error exception from inside
> > 		% lowlevel__write_char
> > 	( impure lowlevel__write_char(Stream, Chr) ->
> > 		true
> > 	;
> > 		semipure Err = lowlevel__error_message(Stream),
> > 		throw(stream_error(Err))
> > 	),
> > 	StreamOut = StreamIn.
> 
> I agree with the XXX comment here -- it would be better to throw
> the exception from inside lowlevel__write_char.
> 
> > %-----------------------------------------------------------------------%
> > % Copyright (C) 2000 The University of Melbourne.
> > % This file may only be copied under the terms of the GNU Library General
> > % Public License - see the file COPYING.LIB
> > %-----------------------------------------------------------------------%
> > %
> > % Module:	tcp
> > % Main Author:	peter.ross at miscrit.be (based on code written by pma at miscrit.be)
> > % Stability:	low
> > %
> > % An implementation of TCP streams.
> > %
> > %-----------------------------------------------------------------------%
> > %-----------------------------------------------------------------------%
> > 

Thanks for the review comments.  This module definately needs some work,
I attached it mainly as an example of using the stream interface.  I
think that it is best to seperate the review of this from the actual
stream implementation.

So I guess the next best step would be for me to submit the stream
implementation for review with an implementation of stdin/out stream,
read file stream and write file stream.

Agreed?

Pete
--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to:       mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions:          mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------



More information about the developers mailing list