On 21 March 2013 20:48, Sven Van Caekenberghe <sven@stfx.eu> wrote:
Hi,
Related to a hard to find Zinc bug that I just discovered, I require some feedback as to the semantics of SocketStream>>#next:
IMHO, the current implementation is semantically wrong. I would expect the semantics to be: try to read count elements and return a new species collection containing them. If less elements are available, return a smaller collection. ( It then becomes effectively a limited #upToEnd).
I always implemented #next: by delegating to #next:into:, to #next:into:startingAt: and finally #readInto:startingAt:count: (see for example ZdcAbstractSocketStream, ZnLimitedReadStream or ZnChunkedReadStream).
When you look at the implementations of #next:into:, #next:into:startingAt: and #readInto:startingAt:count: on SocketStream, the fact that ConnectionClosed is not signalled is clearly stated. Yet SocketStream>>#next: is different, it does signal ConnectionClosed, which makes it impossible (unless you proceed the exception) to read up to end. And this is what InflateStream>>#getFirstBuffer expects. And which fails when less than 65536 bytes are available. Note that InflateStream reads its subsequent buffers using #next:into:startingAt: (see #moveSourceToFront) so that it properly reads up to end without signalling ConnectionClosed for larger payloads.
I can easily program around it, but I think SocketStream>>#next: is wrong and should be changed.
Any opinions ?
Sven
I agree, the implementation notes of #next: should be: - read the N elements from receiver, answer a collection of read elements. if receiver at end, or will reach end before reading all N elements, answer a collection of elements which were successfully read. .. the caller can always check the collection size, and if it < N, (and he insists on having N) he can either throw an error or handle it more graciously. '' readStream next: 5 answering '' so, it actually consistent with what i stating. A reference implementation (in Stream), however doesn't works like that: next: anInteger "Answer the next anInteger number of objects accessible by the receiver." | aCollection | aCollection := OrderedCollection new. anInteger timesRepeat: [aCollection addLast: self next]. ^aCollection this code will always answer collection of N elements.. the bad side of it, that if stream reaching end, the tail will be filled with 'userful' nils. :) so , based on ReadStream implementation we can assume that caller already expects to receive <=N elements, but not N with partly filled with nils. Because then you cannot distinguish whether this nil goes from stream data or from stream itself, e.g.: #( 1 3 nil 4 5 nil nil ) readStream next: 10.
-- Sven Van Caekenberghe http://stfx.eu Smalltalk is the Red Pill
-- Best regards, Igor Stasenko.