[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