Paul Massey's changes to io.m

Fergus Henderson fjh at
Tue Feb 10 03:45:51 AEDT 1998

Hi Paul,

I just had a look at your changes to io.m.

> +% Modifications: P.A.Massey (MC Jul/23/997)
> +%                io__bi_stream type defined and one or two predicates make
> +%                externally visible.

> +:- type io__stream.				% Paul
> +
> +:- type io__bi_stream.				% Paul

> +	% Moved here (Paul) because equivalence is needed
> +	% for sockets to use I/O routines without stream
> +	% type conversions.
> +
> +:- type io__input_stream ==	io__stream.
> +
> +:- type io__output_stream ==	io__stream.
> +
> +:- type io__bi_stream ==	io__stream.   	% Paul.
> +
> +:- type io__binary_stream ==	io__stream.
> +

Hmm.  This has the disadvantage of losing some type checking.
For example, the compiler won't complain if you pass an input_stream
where an output_stream is expected.

I think I might prefer

	:- type bidirectional_stream
		---> bidirectional_stream(

	:- func input(bidirectional_stream) = input_stream.
	input(bidirectional_stream(Input, _Output) = Input.

	:- func output(bidirectional_stream) = input_stream.
	output(bidirectional_stream(_Input, Output) = Output.

This would actually be more general, since it would work for any
pair of input and output streams.  That would mean that you
could write a single routine taking a bidirectional_stream
as a parameter, and it could for example be used both for
network sockets and for stdin/stdout.

Is it really so bad that you have to type

	write_string(output(BidirectionalStream), "What is your name?\n"),
	read_line(input(BidirectionalStream), Result)

instead of 

	write_string(BidirectionalStream, "What is your name?\n"),
	read_line(BidirectionalStream, Result)

?  The extra 7 or 8 characters don't see so bad to me.

>  :- pred io__error_message(io__error, string).
>  :- mode io__error_message(in, out) is det.
> +:- mode io__error_message(out, in) is det. 	% Paul (sockets needed it)
>  %	io__error_message(ErrorCode, ErrorMessage).
>  %		Look up the error message corresponding to a particular error
>  %		code.

I'd prefer a separate predicate

   :- pred io__make_error_message(string, io__error).
   :- mode io__make_error_message(in, out) is det.
   %	io__make_error_message(ErrorMessage, ErrorCode):
   %		Create an io__error value from a user-specified error message.

to better encapsulate the io__error type.
The idea was the io__error might be an integer code (like errno)
or some kind of discriminated union

	:- type io__error
		--->	unix_error(int /* errno */)
		;	library_error(library_error_type)
		;	user_error(string).

Making the predicate bidirectional and det both ways
would mean that io__error must be equivalent to string,
disallowing this sort of implementation.

> +% moved here by Paul.
> +
> +:- pred io__delete_stream_name(io__stream, io__state, io__state).
> +:- mode io__delete_stream_name(in, di, uo) is det.
> +
> +:- pred io__insert_stream_name(io__stream, string, io__state, io__state).
> +:- mode io__insert_stream_name(in, in, di, uo) is det.
> +
> +:- pred io__stream_name(io__stream, string, io__state, io__state).
> +:- mode io__stream_name(in, out, di, uo) is det.

I don't think these need to be exported, if you instead
pass the stream name to io__fd_to_stream.

> +:- pred io__fd_to_stream(int, io__stream, io__state, io__state).
> +:- mode io__fd_to_stream(in, out, di, uo) is det.

Change that to

	:- pred io__fd_to_stream(int, string, io__stream,
					io__state, io__state).
	:- mode io__fd_to_stream(in, in, out, di, uo) is det.

Oh, drat.  Now I see why you wanted to export the type definitions.
Without doing that, we need four different versions:

	:- pred io__fd_to_input_stream(int, string, io__input_stream,
					io__state, io__state).
	:- mode io__fd_to_input_stream(in, in, out, di, uo) is det.

	:- pred io__fd_to_output_input_stream(int, string, io__output_stream,
					io__state, io__state).
	:- mode io__fd_to_output_input_stream(in, in, out, di, uo) is det.

	:- pred io__fd_to_binary_input_stream(int, string,
				io__binary_input_stream, io__state, io__state).
	:- mode io__fd_to_binary_input_stream(in, in, out, di, uo) is det.

	:- pred io__fd_to_binary_output_input_stream(int, string,
				io__binary_output_stream, io__state, io__state).
	:- mode io__fd_to_binary_output_input_stream(in, in, out, di, uo)
				is det.

> +:- pred io__stream_to_fd(io__stream, int, io__state, io__state).
> +:- mode io__stream_to_fd(in, out, di, uo) is det.

We'd need four versions of that too.

In fact, we already export the fact that
binary_output_stream == binary_input_stream,
so we'd only need three versions.


> +/* converts an integer into something which will be acceptable by the 
> + * other IO predicates */
> +
> +:- pragma(c_code, io__fd_to_stream(Fd::in,IOStream::out,IO0::di,IO::uo), "{
> +	MercuryFile *mf;
> +	FILE *f;
> +	f = fdopen(Fd, ""w+"");
> +	if (!f) {
> +		IOStream = NULL;

That will just lead to segmentation faults later.
Better to report an error message and call exit().
Better still would be to change the type for this pred so that it
returns an `io__res(io__stream)' instead of an `io__stream'.

I'm not sure what we should do about this subtyping problem is.
I think the best solution is to add better language support for subtyping.

Fergus Henderson <fjh at>   |  "I have always known that the pursuit
WWW: <>   |  of excellence is a lethal habit"
PGP: finger fjh at         |     -- the last words of T. S. Garp.


More information about the users mailing list