streaming redux

Dmitry Olshansky dmitry.olsh at gmail.com
Thu Dec 30 13:49:15 PST 2010


[snip]
> -----
> Question: Should we allow read to return an empty slice even if atEnd 
> is false? If we do, we allow non-blocking streams with burst transfer. 
> However, naive client code on non-blocking streams will be inefficient 
> because it would essentially implement busy-waiting.
>
> Why not return an integer so different situations could be 
> designated?  It's how the system call read works so you can tell no 
> data was read but that's because it's a non-blocking stream.
>
> I realize it's sexy to return the data again so it can be used 
> immediately, but in practice it's more useful to return an integer. 
>
> For example, if you want to fill a buffer, you need a loop anyways 
> (there's no guarantee that the first read will fill the buffer), and 
> at that point, you are just going to use the length member of the 
> return value to advance your loop.
>
> I'd say, return -1 if a non-blocking stream returns no data, 0 on EOF, 
> positive on data read, and throw an exception on error.
>
Maybe it's only me but I would prefer non-blocking IO not mixed with 
blocking in such a way. Imagine function that takes an 
UnbufferedInputTransport, how should it indicate that it expects only a 
non-blocking IO capable transport? Or the other way around. Checking 
return codes hardly helps anything, and it means supporting both types 
everywhere, which is a source of all kind of  weird problems.
 From my (somewhat limited) experience, code paths for blocking and 
non-blocking IO are quite different, the latter are performed by 
*special* asynchronous calls which are supported by all modern OSes for 
things like files/sockets.

Then my position would be:
1) All read/write methods are *blocking*, returning empty slices on EOF.
2) Transport that supports asynchronous IO should implement extended 
interfaces like
interface AsyncInputTransport: UnbufferedInputTransport{
     void asyncRead(ubyte[] buffer, void delegate(ubyte[] data) 
callback=null);
}
interface AsyncOutputTransport: UnbufferedOutputTransport{
     void asyncWrite(ubyte[] buffer, void delegate(ubyte[] data) 
callback=null);
}
Where callback (if not null) is called with a slice of buffer containing 
actual read/written bytes on IO completion.
Any calls to read/asyncRead while there is asynchronous IO operation 
going on should throw, of course.

Regarding buffering transports I agree with Steven, they shouldn't be 
interfaces *derived* from Unbuffered...Transport.
Speaking of the above the ubyte[] front property of whatever buffered 
range-like construct we settle on IMHO should be blocking, since you 
can't get  any advantage over this by making front return an empty 
slices or throw exceptions on "would block" situations.

-- 
Dmitry Olshansky



More information about the Digitalmars-d mailing list