On Wed, Apr 11, 2018 at 5:33 PM, Sven Van Caekenberghe <s...@stfx.eu> wrote:
> I think we have to reset this whole discussion.
>
>   FileStream stdin
>
> and
>
>   Stdio stdin
>
> are completely different !

Could you explain the difference because I'm dead tired and got confused :)

>
> 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