In other Smalltalk (VW, Dolphin, ...) there is nextAvailable: anInteger "Answer the next anInteger elements of the receiver. If there are not enough elements available, answer a collection of as many as are available." while next: would raise an Error if incomplete... Maybe it's time to adopt it. Nicolas 2013/3/21 Igor Stasenko <siguctua@gmail.com>:
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.