On 4 April 2018 at 12:56, Sven Van Caekenberghe <s...@stfx.eu> wrote:
> Playing a bit devil's advocate, the idea is that, in general,
>
> [ stream atEnd] whileFalse: [ stream next. "..." ].
>
> is no longer allowed ?

It hasn't been allowed "forever" [1].  It's just been misused for
almost as long.

[1] Time began when stdio stream support was introduced. :-)


> And you want to replace it with
>
> [ stream next ifNil: [ false ] ifNotNil: [ :x | "..." true ] whileTrue.
>
> That is a pretty big change, no ?

That's the way quite a bit of code already operates.

As Denis pointed out, it's obviously problematic in the general sense,
since nil can be embedded in non-byte oriented streams.  I suspect
that in practice not many people write code that reads streams from
both byte oriented and non-byte oriented streams.


> I think/feel like a proper EOF exception would be better, more correct.
>
> [ [ stream next. "..." true ] on: EOF do: [ false ] ] whileTrue.

I agree, but the email thread Nicolas pointed to raises some
performance questions about this approach.  It should be
straightforward to do a basic performance comparison which I'll get
around to if other objections aren't raised.


> Will we throw away #atEnd then ? Do we need it if we cannot use it ?

Unix file i/o returns EOF if the end of file has been reach OR if an
error occurs.  You should still check #atEnd after reading past the
end of the file to make sure no error occurred.  Another part of the
primitive change I'm proposing is to return additional information
about what went wrong in the event of an error.

We could modify the read primitive so that it fails if an error has
occurred, and then #atEnd wouldn't be required.

Cheers,
Alistair



>> On 4 Apr 2018, at 12:41, Alistair Grant <akgrant0...@gmail.com> wrote:
>>
>> Hi Nicolas,
>>
>> On 4 April 2018 at 12:36, Nicolas Cellier
>> <nicolas.cellier.aka.n...@gmail.com> wrote:
>>>
>>>
>>> 2018-04-04 12:18 GMT+02:00 Alistair Grant <akgrant0...@gmail.com>:
>>>>
>>>> Hi Sven,
>>>>
>>>> On Wed, Apr 04, 2018 at 11:32:02AM +0200, Sven Van Caekenberghe wrote:
>>>>> Somehow, somewhere there was a change to the implementation of the
>>>>> primitive called by some streams' #atEnd.
>>>>
>>>> That's a proposed change by me, but it hasn't been integrated yet.  So
>>>> the discussion below should apply to the current stable vm (from August
>>>> last year).
>>>>
>>>>
>>>>> IIRC, someone said it is implemented as 'remaining size being zero'
>>>>> and some virtual unix files like /dev/random are zero sized.
>>>>
>>>> Currently, for files other than sdio (stdout, stderr, stdin) it is
>>>> effectively defined as:
>>>>
>>>> atEnd := stream position >= stream size
>>>>
>>>>
>>>> And, as you say, plenty of virtual unix files report size 0.
>>>>
>>>>
>>>>
>>>>> Now, all kinds of changes are being done image size to work around this.
>>>>
>>>> I would phrase this slightly differently :-)
>>>>
>>>> Some code does the right thing, while other code doesn't.  E.g.:
>>>>
>>>> MultiByteFileStream>>upToEnd is good, while
>>>> FileStream>>contents is incorrect
>>>>
>>>>
>>>>> I am a strong believer in simple, real (i.e. infinite) streams, but I
>>>>> am not sure we are doing the right thing here.
>>>>>
>>>>> Point is, I am not sure #next returning nil is official and universal.
>>>>>
>>>>> Consider the comments:
>>>>>
>>>>> Stream>>#next
>>>>>  "Answer the next object accessible by the receiver."
>>>>>
>>>>> ReadStream>>#next
>>>>>  "Primitive. Answer the next object in the Stream represented by the
>>>>>  receiver. Fail if the collection of this stream is not an Array or a
>>>>> String.
>>>>>  Fail if the stream is positioned at its end, or if the position is out
>>>>> of
>>>>>  bounds in the collection. Optional. See Object documentation
>>>>>  whatIsAPrimitive."
>>>>>
>>>>> Note how there is no talk about returning nil !
>>>>>
>>>>> I think we should discuss about this first.
>>>>>
>>>>> Was the low level change really correct and the right thing to do ?
>>>>
>>>> The primitive change proposed doesn't affect this discussion.  It will
>>>> mean that #atEnd returns false (correctly) sometimes, while currently it
>>>> returns true (incorrectly).  The end result is still incorrect, e.g.
>>>> #contents returns an empty string for /proc/cpuinfo.
>>>>
>>>> You're correct about no mention of nil, but we have:
>>>>
>>>> FileStream>>next
>>>>
>>>>        (position >= readLimit and: [self atEnd])
>>>>                ifTrue: [^nil]
>>>>                ifFalse: [^collection at: (position := position + 1)]
>>>>
>>>>
>>>> which has been around for a long time (I suspect, before Pharo existed).
>>>>
>>>> Having said that, I think that raising an exception is a better
>>>> solution, but it is a much, much bigger change than the one I proposed
>>>> in https://github.com/pharo-project/pharo/pull/1180.
>>>>
>>>>
>>>> Cheers,
>>>> Alistair
>>>>
>>>
>>> Hi,
>>> yes, if you are after universal behavior englobing Unix streams, the
>>> Exception might be the best way.
>>> Because on special stream you can't allways say in advance, you have to try.
>>> That's the solution adopted by authors of Xtreams.
>>> But there is a runtime penalty associated to it.
>>>
>>> The penalty once was so high that my proposal to generalize EndOfStream
>>> usage was rejected a few years ago by AndreaRaab.
>>> http://forum.world.st/EndOfStream-unused-td68806.html
>>
>> Thanks for this, I'll definitely take a look.
>>
>> Do you have a sense of how Denis' suggestion of using an EndOfStream
>> object would compare?
>>
>> It would keep the same coding style, but avoid the problems with nil.
>>
>> Thanks,
>> Alistair
>>
>>
>>
>>> I have regularly benched Xtreams, but stopped a few years ago.
>>> Maybe i can excavate and pass on newer VM.
>>>
>>> In the mean time, i had experimented a programmable end of stream behavior
>>> (via a block, or any other valuable)
>>> http://www.squeaksource.com/XTream.htm
>>> so as to reconcile performance and universality, but it was a source of
>>> complexification at implementation side.
>>>
>>> Nicolas
>>>
>>>>
>>>>
>>>>> Note also that a Guille introduced something new, #closed which is
>>>>> related to the difference between having no more elements (maybe right 
>>>>> now,
>>>>> like an open network stream) and never ever being able to produce more 
>>>>> data.
>>>>>
>>>>> Sven
>
>

Reply via email to