[phobos] Improvement of stream

Andrei Alexandrescu andrei at erdani.com
Sat Sep 4 23:40:27 PDT 2010


As I alluded before, I agree that a streaming interface is useful. 
Moreover, probably File should implement it. I suggest we proceed with 
defining and using streaming interfaces for input and output on a 
per-need basis.

Andrei

On 07/06/2010 06:04 AM, SHOO wrote:
> Thanks for your reply.
>
> Perhaps Stream which you imagine and Stream which I imagine are
> different. Stream which I imagine corresponds approximately to File and
> Socket and so on.
> The name may be bad. And I think it to be close in Handle which you say.
> Even if the name is Handle, Resource or Device, etc. , I will accept it.
> (For convenience, in my sentence of this time, I unify it in Stream.)
> Addition template to input device would bring general versatility to
> Ranges for streaming.
>
> Please take it into consideration.
>
>
> (2010/07/05 14:37), Andrei Alexandrescu wrote:
>> Hello,
>>
>>
>> I've been looking over the streaming proposal. Allow me to make a few
>> comments:
>>
>> - The input ranges _are_ intended to be input streams, and the output
>> ranges _are_ intended to be output streams. If they don't fulfill that
>> purpose, they should be changed (instead of adding new categories).
>>
>
> Firstly I said, The input ranges are not intended to be input streams
> which I imagine. The input ranges are more high level interface that
> _use_ streams.
>
>> - Input streams have the read primitive. What is wrong with an input
>> range of ubyte[]? Then accessing front() gives you a buffer and popFront
>> reads in a new buffer.
>>
>
> For example, reading of binary data from Stream for initialization of
> following struct data is like a nightmare:
> struct S{
> int a;
> ubyte[] b;
> double c;
> }
>
> For this initialization, you will read data that has different size
> least 4 times.
> You might try following code:
>
> File f;
> ... = f.byChunk(4);
> ... = f.byChunk(size_t.sizeof);
> ... = f.byChunk(s.b.length);
> ... = f.byChunk(8);
>
> I hardly see it effectively. And I think we should become careful to
> complicate Range more than current one.
>
>> - What does flush() do for input streams?
>>
>
> I don't think deeply. File.rewind() may correspond to this.
>
>> - I don't think close() is a good primitive for an input stream. An
>> input stream should originate in a connection handle, and it's the
>> handle, not the stream, that should control the connection. For example:
>>
>> auto s = Socket("123.456.455.1");
>> auto stream = s.byChunk(1024 * 16);
>> ... stream is an input range of ubyte[] ...
>> s.close();
>>
>> If the range defines a close() operation, then we need to start talking
>> about it defining an open() operation, which complicates matters. Why
>> not leave ranges for traversal and handles for connections?
>>
>
> Maybe, your Handle is similar to my Stream.
> The open() operation can replace it by a constructor, but the close()
> operation is substitute impossibility by destructor.
> Because, destructor may not be called when a struct data managed by GC.
> The story is different if D offers a method to perform better RTTI.
>
>> - On to output streams. What's wrong with having an output range of
>> ubyte[]? Its put() primitive would be the same as the proposed write()
>> routine.
>>
>
> I think it is good idea that Ranges for OutputStream. Now,
> LockingTextWriter just likes this.
>
>> - flush() would be a good optional addition to an output stream.
>>
>
> Do you mean BufferedRange? It's interesting.
>
>> - I have the same feeling about close() for output streams.
>>
>
> Me too.
>
>> - The Seekable idea is good, I was thinking of it for a while. It
>> expresses a range that is not as cheap for random access as a
>> random-access range, but also that makes random seeking possible. What
>> kind of algorithms could use Seekable?
>>
>
> I think that Seekable is unnecessary for Range.
> Seekable should be had by Stream. In Container, slice is this.
>
>> - What's the purpose of StreamWrapper? And why is it reading in the
>> write() primitive?
>>
>
> For override.
>
> interface X {
> InputStream getInputStream();
> }
> class Y: X {
> InputStream getInputStream(){ return wrap(FileStream("/path/to/file")); }
> }
> class Z: X {
> InputStream getInputStream(){ return wrap(SocketStream(socket)); }
> }
>
> Or, for arrays.
>
> InputStream[] ins;
> ins ~= wrap(FileStream("/path/to/file"));
> ins ~= wrap(SocketStream(socket));
>
> wrap is workaround for case that someone wants to employ interface by
> all means. If override of template function is possible, the story may
> be different.
>
> And sorry, reading in the write() primitive is my miss.
>
>> - ByLine is a bit awkward because it needs to read buffers of size 1.
>> Clearly there is some problem there. The right way is to build
>> ByLine!Char on top of a stream of Char, not a stream of Char[].
>> (Speaking of which, I just checked in BlockingInputReader. It does read
>> one character at a time but it has an inefficiency caused by the FILE*
>> interface.)
>>
>
> I think so, too. Because it is only a mere demonstration, the
> implementation is slipshod.
>
>> - What does FileStream do that File doesn't or can't do?
>>
>
> It is just an Adapter.
>
>> Let me know of what you think.
>>
>>
>> Andrei
> _______________________________________________
> phobos mailing list
> phobos at puremagic.com
> http://lists.puremagic.com/mailman/listinfo/phobos


More information about the phobos mailing list