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

Fergus Henderson fjh at cs.mu.OZ.AU
Thu Sep 28 16:47:38 AEDT 2000


On 28-Sep-2000, Michael Day <mcda at students.cs.mu.oz.au> wrote:
> 
> > Hmm, that raises another problem: what about the singleton variables
> > `StreamA1' and `StreamB1' in this example?  If these streams are I/O
> > streams, whose updates have externally visible side effects, don't you
> > need some way to tie those variables back into the final io__state
> > returned from main?  Otherwise the compiler could just optimize away
> > all the stuff in curlies, since it is det and has no output variables
> > except the singletons, whose scope is local to that goal.
> 
> Time to split that pesky io__state again :)
> 
> :- open(stream::uo, io__state(T)::di, io__state(io__state(T))::uo) is det.
> 
> :- close(stream::di, io__state(io__state(T))::di, io__state(T)::uo) is det.
>
> Now every open stream must be closed or there will be a compile error,
> assuming io__state is parameterized by T and main looks like this:
> 
> :- pred main(io__state(T)::di, io__state(T)::uo) is whatever.

If we're going to do that kind of thing, i.e. encoding the number of open
streams as a type parameter to the io__state expressed in unary notation,
then I'd rather we used a different type than `io__state' for the
parameters, i.e.

	% The following types are used to represent the number of
	% open streams using unary (successor) notation.
	:- type io__nil.  % no open streams
	:- type io__s(T). % one more open stream than T
	% Alternatively the `io__s' type could be named `io__succ'
	% or `io__successor', depending on how verbose you want to be...

	:- open(stream::uo, io__state(T)::di, io__state(io__s(T))::uo) is det.
	:- close(stream::di, io__state(io__s(T))::di, io__state(T)::uo) is det.

Even though there are more type names, I think this will make things
less confusing, particularly when printing out types in the debugger
and in compiler error messages.

> Alternatively if people don't like to change the definition of main, we
> can define these:
> 
> :- begin_stream_stuff(io__state::di, io__funky_state(nil)::uo) is det.
> 
> :- end_stream_stuff(io__funky_state(nil)::di, io__state::uo) is det.
> 
> So you can call begin_stream_stuff to get a funky_state, then open streams
> with that, and all streams must be closed before you can call
> end_stream_stuff to get back your old io__state to return from main. I'd
> prefer the former, though.

Here I think it would be OK to just name `io__funky_state/1' as
`io__state/1' and to use arity overloading to distinguish between
io__state/0 and io__state/1.

We could even avoid the need for explicit calls to begin_stream_stuff
and end_stream_stuff by defining `io__state' as

	:- type io__state == io__state(io__nil).

However, any code using io__state/0 would be less reusable than it
ought to be -- it could only be called on I/O states that have no open
streams.  So although there would be some degree of backwards compatibility,
this approach would still require sweeping changes to existing code if
you want to make use of streams and interoperate with that existing code.

However, I think there is a major flaw in all of these approaches:
what happens with `try_io'?  When you throw an exception, you may skip
an unknown number of calls to `close'.  The io__state at the end of
try_io is unspecified, so skipping the calls to `close' doesn't
cause any semantic problems, but the approach fails its intended goal
of ensuring that every open stream is closed, so there's a serious
practical problem.  The only way to avoid this problem would be
to wrap the code between calls to `open' and `close' with an
exception handler that called `close' and then rethrew the
exception.

If you need to do that, then you might as well just provide a
higher-order `with_stream' procedure rather than providing `open' and
`close', so that programmers don't need to rewrite that exception
handling code each time.  And once you do that, then you don't
actually need the extra parameter to the io__state type.

	:- pred with_stream(pred(stream(S)::di, stream(S)::uo),
                io__state::di, io__state::uo).

-- 
Fergus Henderson <fjh at cs.mu.oz.au>  |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>  |  of excellence is a lethal habit"
PGP: finger fjh at 128.250.37.3        |     -- the last words of T. S. Garp.
--------------------------------------------------------------------------
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