I think we have to reset this whole discussion.

  FileStream stdin 

and

  Stdio stdin

are completely different !

We'll have to check that first, before talking about the issues raised in this 
thread.

And BTW these terminal streams are a real pain to test ;-)

> On 11 Apr 2018, at 17:20, Sven Van Caekenberghe <s...@stfx.eu> wrote:
> 
> 
> 
>> On 11 Apr 2018, at 17:16, Denis Kudriashov <dionisi...@gmail.com> wrote:
>> 
>> 
>> 2018-04-11 17:02 GMT+02:00 Sven Van Caekenberghe <s...@stfx.eu>:
>> 
>> 
>>> On 11 Apr 2018, at 16:36, Sven Van Caekenberghe <s...@stfx.eu> wrote:
>>> 
>>> I can make your example, using the Zn variants, work with the following 
>>> change:
>>> 
>>> StdioStream>>#atEnd
>>> ^ peekBuffer isNil or: [ (peekBuffer := self next) isNil ]
>> 
>> Argh, make that
>> 
>> atEnd
>>  ^ peekBuffer isNil and: [ (peekBuffer := self next) isNil ]
>> 
>> But discussion exactly about "self next isNil": how to avoid it.
> 
> I know, but like this it could/might become an implementation detail.
> 
> The more things that I try, the more that I feel that stdin is so special 
> that it does not fit in the rest of the stream zoo.
> 
>> but I am still testing, this is probably not the final answer/solution.
>> 
>>> Which is a literal implementation of your statement that you can only know 
>>> that you are atEnd by reading (and thus waiting/blocking) and checking for 
>>> nil, which seems logical to me, given the fact that you *are* waiting for 
>>> user input.
>>> 
>>> BTW, at least on macOS you have to enter ctrl-D (^D) on a separate line, I 
>>> am not sure how relevant that is, but that is probably another argument 
>>> that stdin is special (being line-buffered by the OS, EOF needing to be on 
>>> a separate line).
>>> 
>>> And FWIW, I have been writing networking code in Pharo for years, and I 
>>> have never had issues with unclear semantics of these primitives (#atEnd, 
>>> #next, #peek) on network streams, either the classic SocketStream or the 
>>> Zdc* streams (TLS or not). That is why I think we have to be careful.
>>> 
>>> That being said, it is important to continue this discussion, I find it 
>>> very interesting. I am trying to write some test code using stdin myself, 
>>> to better understand the topic.
>>> 
>>>> On 11 Apr 2018, at 16:06, Alistair Grant <akgrant0...@gmail.com> wrote:
>>>> 
>>>> On 11 April 2018 at 15:11, Sven Van Caekenberghe <s...@stfx.eu> wrote:
>>>>> 
>>>>> 
>>>>>> On 11 Apr 2018, at 11:12, Sven Van Caekenberghe <s...@stfx.eu> wrote:
>>>>>> 
>>>>>> How does one modify #atEnd to block ? I suppose you are talking about 
>>>>>> StdioStream>>#atEnd ?
>>>>>> 
>>>>>> ^ self peek isNil
>>>>>> 
>>>>>> ?
>>>>> 
>>>>> Still the same question, how do you implement a blocking #atEnd for stdin 
>>>>> ?
>>>>> 
>>>>> I have seen your stdio.cs which is indeed needed as the current 
>>>>> StdioStream>>#atEnd is bogus for sure.
>>>>> 
>>>>> But that is still a non-blocking one, right ?
>>>>> 
>>>>> Since there is a peekBuffer in StdioStream, why can't that be used ?
>>>> 
>>>> I think you've created a chicken-and-egg problem with this question,
>>>> but ignoring that for now:
>>>> 
>>>> 
>>>> StdioStream>>peek
>>>> "Answer what would be returned if the message next were sent to the
>>>> receiver. If the receiver is at the end, answer nil.  "
>>>> 
>>>>  self atEnd ifTrue: [^ nil ].
>>>> 
>>>>  peekBuffer ifNotNil: [ ^ peekBuffer ].
>>>> 
>>>>  ^ peekBuffer := self next.
>>>> 
>>>> 
>>>> 
>>>> So when we first start the program, i.e. the user hasn't entered any
>>>> input yet, and #peek is called:
>>>> 
>>>> 1. #atEnd returns false because Ctrl-D (or similar) hasn't been
>>>> entered (assuming it is non-blocking).
>>>> 2. peekBuffer is nil because we haven't previously called #peek.
>>>> 3. The system now blocks on "self next".
>>>> 
>>>> 
>>>> Just a reminder: for terminal input the end-of-file isn't reached
>>>> until the user explicitly enters the end of file key (Ctrl-D).
>>>> 
>>>> So, if there is no buffered input (either none has been entered yet,
>>>> or all input has been consumed)
>>>> 
>>>> #atEnd (after the patch) calls #primAtEnd:.
>>>> 
>>>> At the moment, #primAtEnd: ends up calling the libc function feof(),
>>>> which is non-blocking and answers the end-of-file flag for the FILE*.
>>>> Since the user hasn't entered Ctrl-D, that's false.
>>>> 
>>>> If we want to control iteration over the stream and ensure that we
>>>> don't need to do a "stream next == nil" check, then #primAtEnd: is
>>>> going to have to peek for the next character, and that means waiting
>>>> for the user to enter that character.
>>>> 
>>>> In c that is typically done using:
>>>> 
>>>> atEnd = ungetc(fgetc(fp), fp);
>>>> 
>>>> and fgetc() will block until the user enters something.
>>>> 
>>>>> I have run your example testAtEnd.st now, and it works/fails as 
>>>>> advertised.
>>>> 
>>>> :-)
>>>> 
>>>> 
>>>> Cheers,
>>>> Alistair


Reply via email to