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