[Pharo-project] [squeak-dev] #ensure: issues (was: Re: Pharo by Example vol 2: new chapter available)

Levente Uzonyi leves at elte.hu
Wed Mar 3 22:07:01 UTC 2010


On Wed, 3 Mar 2010, Igor Stasenko wrote:

> 2010/3/3 Levente Uzonyi <leves at elte.hu>:
>> On Wed, 3 Mar 2010, Igor Stasenko wrote:
>>
>>> 2010/3/3 Levente Uzonyi <leves at elte.hu>:
>>>>
>>>> On Wed, 3 Mar 2010, Igor Stasenko wrote:
>>>>
>>>>> 2010/3/3 Levente Uzonyi <leves at elte.hu>:
>>>>>>
>>>>>> On Tue, 2 Mar 2010, Igor Stasenko wrote:
>>>>>>
>>>>>>> 2010/3/2 Levente Uzonyi <leves at elte.hu>:
>>>>>>> On Tue, 2 Mar 2010, Henrik Sperre Johansen wrote:
>>>>>>>
>>>>>>>>
>>>>>>>>>> PS. For the not-so-faint-of-heart, open a Transcript and try
>>>>>>>>>> evaluating:
>>>>>>>>>> |proc|
>>>>>>>>>> proc := [[Transcript show: 'Start!'. ] ensure: [Transcript show:
>>>>>>>>>> 'Finish!' Processor yield.]] newProcess.
>>>>>>>>>> proc resume.
>>>>>>>>>> Processor yield.
>>>>>>>>>> proc suspend.
>>>>>>>>>> proc terminate.
>>>>>>>>>
>>>>>>>>> Why don't we get it printing?
>>>>>>>>
>>>>>>>> Forgot a . there, supposed to be
>>>>>>>>
>>>>>>>> |proc|
>>>>>>>> proc := [[Transcript show: 'Start!'. ] ensure: [Transcript show:
>>>>>>>> 'Finish!'. Processor yield.]] newProcess.
>>>>>>>> proc resume.
>>>>>>>> Processor yield.
>>>>>>>> proc suspend.
>>>>>>>> proc terminate.
>>>>>>>>
>>>>>>>> on my machine it prints:
>>>>>>>> *Start!Start!Finish!
>>>>>>>
>>>>>>> The problem occurs because Transcript >> #endEntry (sent from #show:)
>>>>>>> takes a while to execute, so the process (proc) prints 'Start!', but
>>>>>>> it gets terminated before execution reaches #resetContents (#reset in
>>>>>>> Squeak). So 'Start!' is still in the stream. Then our process executes
>>>>>>> the
>>>>>>> #ensure: block and it prints 'Start!' and 'Finish!' too.
>>>>>>>
>>>>>>> There's worse problem with #ensure: and #terminate is that, a process
>>>>>>> executing an #ensure: block can be terminated. If you evaluate this
>>>>>>> code:
>>>>>>>
>>>>>>> | process stage1 stage2 stage3 counter |
>>>>>>> stage1 := stage2 := stage3 := false.
>>>>>>> counter := 0.
>>>>>>> process := [
>>>>>>>        [ stage1 := true ] ensure: [
>>>>>>>                stage2 := true.
>>>>>>>                1000000 timesRepeat: [ counter := counter + 1 ].
>>>>>>>                stage3 := true ] ] newProcess.
>>>>>>> process resume.
>>>>>>> Processor yield.
>>>>>>> process suspend.
>>>>>>> process terminate.
>>>>>>> 1000 milliSeconds asDelay wait.
>>>>>>> { stage1. stage2. stage3. counter } explore
>>>>>>>
>>>>>>> you will find that stage1 and stage2 is reached as expected, but
>>>>>>> stage3
>>>>>>> is
>>>>>>> not and counter is less than 1000000. That's because the forked
>>>>>>> process
>>>>>>> started evaluating the #ensure: block, but it was terminated by our
>>>>>>> process.
>>>>>>>
>>>>>>> Is this the expected behavior when sending #terminate to a process
>>>>>>> which
>>>>>>> is
>>>>>>> evaluating an #ensure: block?
>>>>>>>
>>>>>>>
>>>>>> What you think is expected behavior here:
>>>>>>
>>>>>> a) process termination should start (be triggered) only when process
>>>>>> is outside of any #ensure: closure?
>>>>>> b) #ensure: block should always run to the end, despite anything?
>>>>>>
>>>>>> Since you can't predict, what code will run inside ensure block, the
>>>>>> only guarantee that you having is actually
>>>>>> that your process will always enters such blocks during the normal
>>>>>> flow, or exception handling. But there is no guarantees that it will
>>>>>> be able to run the code inside it, when you terminating it.
>>>>>>
>>>>>>
>>>>>> I'd expect it to be evaluated no matter what happens.
>>>>>>
>>>>> even this one?
>>>>> [self boom ] ensure: [ self halt. Transcript show: 'boom']
>>>>
>>>> Yes.
>>>>
>>> so, even if you click 'abandon' in debugger popup, its still should
>>> print 'boom' in transcript?
>>
>> I didn't say that. I said evaluate it the same way as normal code.
>
> Please define, what is 'normal' code. If you maybe know, exceptions
> and stack unwinding implemented in smalltalk, there's no any 'magic'
> and this code interpreted by VM as any other code, which makes it as
> 'normal' as any other one.
>
>> If you evaluate this code:
>>
>> self halt. Transcript show: 'boom'.
>>
>> and press abandon, then Transcript show: 'boom' will not be executed.
>>
>
> i don't get it. Just before that, you said: ' I'd expect it to be
> evaluated no matter what happens.' ?
> But now you saying that it may not be executed in some conditions
> (when user pressing abandon button, causing process to be terminated).

It's simple: don't terminate process X from another process if process X 
is executing a termiation block (aka #ensure: block). Or if you terminate 
it, make sure that the execution of the block will continue somehow (I 
don't care how).
I think every user of #ensure: expects that the termination blocks are 
executed even if the process which is executing the receiver of #ensure: 
is terminated. And it actually happens in all but this case.


Levente

>
>>
>> Levente
>>
>>>
>>>>
>>>> Levente
>>>>
>>>>>
>>>>>
>>>>>>
>>>>>> Levente
>>>>>>
>>>>>>
>>>
>>>
>>>
>>>
>>> --
>>> Best regards,
>>> Igor Stasenko AKA sig.
>>>
>>
>>
>>
>>
>
>
>
> -- 
> Best regards,
> Igor Stasenko AKA sig.
>
>


More information about the Squeak-dev mailing list