[squeak-dev] Re: [Pharo-project] #ensure: issues

Igor Stasenko siguctua at gmail.com
Thu Mar 4 02:10:31 UTC 2010

2010/3/4 Levente Uzonyi <leves at elte.hu>:
> On Thu, 4 Mar 2010, Igor Stasenko wrote:
>> 2010/3/4 Levente Uzonyi <leves at elte.hu>:
>>> On Thu, 4 Mar 2010, Igor Stasenko wrote:
>>>> On 4 March 2010 01:56, Nicolas Cellier
>>>> <nicolas.cellier.aka.nice at gmail.com> wrote:
>>>>> 2010/3/4 Levente Uzonyi <leves at elte.hu>:
>>>>>> On Thu, 4 Mar 2010, Nicolas Cellier wrote:
>>>>>>> 2010/3/3 Levente Uzonyi <leves at elte.hu>:
>>>>>>>> On Wed, 3 Mar 2010, Andreas Raab wrote:
>>>>>>>>> On 3/3/2010 2:07 PM, Levente Uzonyi wrote:
>>>>>>>>>> On Wed, 3 Mar 2010, Igor Stasenko wrote:
>>>>>>>>>>> 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).
>>>>>>>>> You're missing Igors point which is that in his example the halt /
>>>>>>>>> Transcript *was* in the ensure block and as a result you're
>>>>>>>>> contradicting
>>>>>>>>> yourself here. Let's go back to Igor's example:
>>>>>>>>> [self boom ] ensure: [ self halt. Transcript show: 'boom']
>>>>>>>>> The halt is inside the ensure block. If you terminate the process
>>>>>>>>> from
>>>>>>>>> the
>>>>>>>>> debugger, it would be logical from your statement that the
>>>>>>>>> Transcript
>>>>>>>>> message would be executed - after all it's " executing a termiation
>>>>>>>>> block
>>>>>>>>> (aka #ensure: block)" and so it can't be terminated by your
>>>>>>>>> reasoning.
>>>>>>>>> However, when Igor was pointing this out you replied with "I didn't
>>>>>>>>> say
>>>>>>>>> that. I said evaluate it the same way as normal code." which is
>>>>>>>>> inconsistent
>>>>>>>>> with the other statement.
>>>>>>>> That shows my lack of knowledge about how the debugger works.
>>>>>>>>>> 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.
>>>>>>>>> The question of terminating processes is always tricky. I don't
>>>>>>>>> think
>>>>>>>>> that
>>>>>>>>> your proposal would actually work in practice - it could easily
>>>>>>>>> result
>>>>>>>>> in
>>>>>>>>> processes that cannot be terminated due to a simple bug in an
>>>>>>>>> ensure
>>>>>>>>> block.
>>>>>>>>> Personally, I'd rather say that the more useful behavior would be
>>>>>>>>> something
>>>>>>>>> along the lines of saying that process termination either skips the
>>>>>>>>> current
>>>>>>>>> ensure block (assuming there's a bug and it should get the heck out
>>>>>>>>> of
>>>>>>>>> it
>>>>>>>>> but try to evaluate the remaining ones) or that there need to be
>>>>>>>>> two
>>>>>>>>> terminations - one that is 'soft' and won't allow ensure blocks to
>>>>>>>>> be
>>>>>>>>> skipped and one that is 'hard' (kill -9 hard) and just ignores all
>>>>>>>>> the
>>>>>>>>> ensure blocks.
>>>>>>>> I'm only saying that normal usage (aka #terminate) shouldn't do
>>>>>>>> unexpected
>>>>>>>> things like this.
>>>>>>>> If you read the comment of Process >> #terminate, you may assume
>>>>>>>> that
>>>>>>>> #ensure: and #ifCurtailed: blocks will be excuted even if you use
>>>>>>>> #terminate, but that's not true.
>>>>>>>> "Stop the process that the receiver represents forever.  Unwind to
>>>>>>>> execute
>>>>>>>> pending ensure:/ifCurtailed: blocks before terminating."
>>>>>>>> Levente
>>>>>>> The only way I see to solve your problem would be to execute the
>>>>>>> unwind block in another process...
>>>>>>> Quite technical and costly !
>>>>>> It's our problem. Just look at the senders of #ensure: and imagine
>>>>>> what
>>>>>> will
>>>>>> happen if the termination block is not evaluated.
>>>>>> I think there's another way (though it might be my lack of knowledge
>>>>>> again).
>>>>>> After suspending the process which is about to be terminated we can
>>>>>> check if
>>>>>> it's executing a termination block. It it's not, we are safe to
>>>>>> continue
>>>>>> the
>>>>>> termination, otherwise we can do something else which ensures that the
>>>>>> termination block is evaluated.
>>>>> Maybe...
>>>>> Unfortunately, you did not tell how you will distinguish well behaved
>>>>> unwind-blocks from Igor's example...
>>>> Yes, then what prevents me from writing:
>>>> [ [ ] ensure: [ self doCrazyThings ] ] fork.
>>> What prevents you from writing: Object superclass: Object. ?
>>> Nothing, but you don't do that, do you?
>> So, why at all, you care about using #ensure: then? If you putting
>> everything up to the hands of developer,
>> then obviously you won't need to use this message, because you always
>> know that you're running a reliable code which
>> will always let you to run your things in the end. :)
>>>> and now given assumption that any code which placed inside ensure
>>>> block should always run to the end, without chances being terminated,
>>>> will have ill side effects.
>>> You can terminate it (maybe not the usual way).
>> that's the point. Why do we need two (or more) ways to terminate a
>> process?
>>>> The #ensure: means, that interpreter will have a chance to enter that
>>>> block eventually, but it should not mean that it will keep running the
>>>> code there until normal or non-local return from that block.
>>> Then it doesn't ensure anything at all, so it should be called
>>> #tryToEvaluateThisToo:.
>> in fact, this is the actual behavior :)
>> If i press the power button on your PC, or plug out the power cord,
>> any #ensure: blocks will have no chances to run either way.
>> So, relying on something, which is not reliable is a fallacy :)
> Here's a simple example (replace file with any external resource):
> My process opened a file, a termination block will close it if it's
> evaluated. If I send #terminate to the process I expect my file to be
> closed, so I won't leak a file descriptor.
> If the file can't be closed (aka the termination block raised an error) then
> there's a serious problem. It doesn't really matter what happens then.
> But I don't have to try to convince you anymore, because Andreas is about to
> solve the issue.

I'm not trying to convince anyone, i just wanted to show you that
there is no good solution in that plane.
More workarounds means more code to run (and makes things more complex, btw).
But you will be still unsafe.You will be safe, once you stop relying
on #ensure: in your code and use different approach.

As for your example: use weak finalizer to close your file.
This will make sure that no matter what were happen, you wont leave
the file open. Working with external resources is a pain. But lets try
to not poison ourselves with manual resource management, which comes
from C world.

> Levente
>>> Levente
>>>> Othewise, you losing a way to terminate unwanted, ill-behaved process.
>>>>> Nicolas
>>>>>> Levente
>>>>>>> Nicolas
>>>>>>>>> Cheers,
>>>>>>>>>  - Andreas
>>>> --
>>>> Best regards,
>>>> Igor Stasenko AKA sig.
>> --
>> Best regards,
>> Igor Stasenko AKA sig.

Best regards,
Igor Stasenko AKA sig.

More information about the Squeak-dev mailing list