[m-dev.] stream typeclasses (again)

Ian MacLarty maclarty at cs.mu.OZ.AU
Wed Mar 8 09:35:58 AEDT 2006


On 6 Mar 2006, at 01:05, Julien Fischer wrote:

>
> On Sun, 5 Mar 2006, Ian MacLarty wrote:
>
>> On 28 Feb 2006, at 08:03, Julien Fischer wrote:
>>
>>> I've spent a bit more time playing around with the stream typeclass
>>> proposal.
>>> Attached is the (or at least my) latest version plus a number of
>>> example
>>> streams.  (Ian, I think you mentioned you'd done some more work on
>>> this as
>>> well?)
>>>
>>> Major changes from last time:
>>>
>>> * The error type is now part of the stream typeclass, (it's
>>> functionally
>>>   dependent on the stream type).
>>>
>>> * The close method has been removed (for the moment at least)
>>>
>>
>> I think there may have been a misunderstanding about what the State
>> argument of the stream typeclass is for.  It's supposed to be the 
>> state
>> that is modified when you read or write from the stream, so for the
>> buffer stream it would be the string type.
>
> There was no misunderstanding on my end.  The problem that I was 
> trying to
> avoid by not making the state the string was the following:
>
> Imagine I create two string buffers, let's call them <<ian>> and 
> <<julien>>.
> Associated with each I have two states.  Let's say the initial state 
> for
> <<ian>> is Ian0 = "maclarty" and the initial state for <<julien> is 
> Julien0 =
> "fischer".  I wrote the buffer type the way I did in order to stop you 
> doing
> things like this.
>
> 	put(<<julien>>, "abc", Ian0, Ian).
>

Ah, I see why you did it like that now.  Do you think this type of 
situation will be a problem in practice?  I can't imagine people would 
get their julien's and ian's mixed up all that often...

> Under the new version of the string buffer there is no connection 
> between
> the identity of a stream and its current contents.  This was raised in 
> a
> previous post by Doug Auclair, i.e. what do you do when the stream is
> the same as the state.  One solution I've been toying with is adding
> another kind of stream to the stream hierarchy, something like:
>
> 	:- typeclass stream(S) where [].
>
> 	:- typeclass input_stream(Unit, Stream) where [
> 		pred get(Unit::out, Stream::in, Stream::out) is det
> 	].
>
> 	:- typeclass output_stream(Unit, Stream) where [
> 		pred put(Unit::in, Stream::in, Stream::out) is det
> 	].
>
> This would allow string buffers of the type you suggest above (it would
> also work in contexts that allow backtracking which might be nice for
> string buffers).
>

Yes, but it has the disadvantage that predicates designed to work with 
other streams won't work with the above streams.  So for example you 
couldn't write xml to a string, unless you implemented two versions of 
write_xml_doc.

Now if we had nested uniqueness and polymorphic modes, then we could 
implement all streams like your suggestion above (since we could embed 
the IO state in the stream type)...

>> I've rewritten the buffer module and attached it.  At the moment it
>> doesn't take advantage of the unique modes, so we could make it more
>> efficient by doing destructive update of the string with foreign code.
>>
>> Also I think the encryption typeclass should be implemented
>> differently.  Instead of writing to the stream to encrypt the data, 
>> and
>> then reading from the same stream to get the encrypted data, I would
>> add an extra argument to the 'new' predicate that creates the stream.
>> The extra argument would be the stream to write the encrypted data to.
>
> The encryption stream example was just an example of a duplex stream.
>
>> Consider the situation where you're implementing an encrypted file
>> transfer protocol.  Using your design you'd have to either write the
>> whole file to the encryption stream and then read it and forward it to
>> a socket stream (which would exhaust memory if the file was big), or
>> implement some kind of buffering system that would flush the 
>> encryption
>> stream to the socket at regular intervals.  Using my proposed design
>> you'd just create the encryption stream, giving the socket stream as 
>> an
>> argument, then everytime you write to the encryption stream the
>> encrypted data automatically gets forwarded to the socket stream.
>>
>> In trying to implement this design though I hit some restrictions in
>> the typeclass system which I think probably don't need to be there.
>> I'll describe these in a separate email.
>>
>> I still think the 'name' method shouldn't need to alter the state.
>> Perhaps we should do away with that method.  I can't see it being
>> particularly useful, since I imagine you'd only use the stream name in
>> error messages, which can be done by including the name in the Error
>> type for the stream.
>
> You certainly want the ability to print out filenames in other 
> contexts.
> `mmc -V' prints out lots of filenames in things that aren't error 
> messages.
> I don't see why more general streams would be any different.
>
> I agree the 'name' method shouldn't need to alter the state, but that's
> a relatively minor issue.
>

Okay.

>> Another issue we haven't addressed that we will need to before we
>> update the std library is what will the notion of the current stream
>> mean?  Since we can't store a general stream in a global mutable (and
>> it doesn't really make sense to anyway), should we just have the 
>> notion
>> of the current *file* stream?
>
> Current file stream is trivial to implement ;-), so I suggest we just 
> go
> with that for now.
>

Okay.

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