[Pharo-project] Pharo by Example vol 2: new chapter available
Hi guys We just released a new chapter for Pharo by Example Vol.2 on Exceptions http://pharobyexample.org/ Let us know what you think. Stef
Stef, It look good. You seem to do a nice job of describing when to use exceptions, and when/how to avoid them (e.g. #at:ifAbsent:). Bill ________________________________________ From: pharo-project-bounces@lists.gforge.inria.fr [pharo-project-bounces@lists.gforge.inria.fr] On Behalf Of Stéphane Ducasse [stephane.ducasse@inria.fr] Sent: Tuesday, March 02, 2010 8:26 AM To: Pharo-project Development Subject: [Pharo-project] Pharo by Example vol 2: new chapter available Hi guys We just released a new chapter for Pharo by Example Vol.2 on Exceptions http://pharobyexample.org/ Let us know what you think. Stef _______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
;) On Mar 2, 2010, at 3:30 PM, Schwab,Wilhelm K wrote:
Stef,
It look good. You seem to do a nice job of describing when to use exceptions, and when/how to avoid them (e.g. #at:ifAbsent:).
Bill
________________________________________ From: pharo-project-bounces@lists.gforge.inria.fr [pharo-project-bounces@lists.gforge.inria.fr] On Behalf Of Stéphane Ducasse [stephane.ducasse@inria.fr] Sent: Tuesday, March 02, 2010 8:26 AM To: Pharo-project Development Subject: [Pharo-project] Pharo by Example vol 2: new chapter available
Hi guys
We just released a new chapter for Pharo by Example Vol.2 on Exceptions http://pharobyexample.org/
Let us know what you think.
Stef
_______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
_______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
On 02.03.2010 14:26, Stéphane Ducasse wrote:
Hi guys
We just released a new chapter for Pharo by Example Vol.2 on Exceptions http://pharobyexample.org/
Let us know what you think.
Stef On p4 there's an error, it says ensure: and ifCurtailed are implemented as primitives, in fact they use the exact same implementation as described of the exception handling in 15.1, the primitive is only used as a marker, and the primitive is required to fail for them to work :) In addition, I'm not too sure what sense it makes to show how to implement one with the other (nor that the implementations are actually correct, f.ex. ifCurtailed: block does not trigger on non-local returns...)
Other than that, very nice chapter! Especially liked 1.9 - 1.13, with the thorough explanation of the different ways an exception can be returned from. Cheers, Henry 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.
On Mar 2, 2010, at 8:47 PM, Henrik Sperre Johansen wrote:
On 02.03.2010 14:26, Stéphane Ducasse wrote:
Hi guys
We just released a new chapter for Pharo by Example Vol.2 on Exceptions http://pharobyexample.org/
Let us know what you think.
Stef On p4 there's an error, it says ensure: and ifCurtailed are implemented as primitives, in fact they use the exact same implementation as described of the exception handling in 15.1, the primitive is only used as a marker, and the primitive is required to fail for them to work :) In addition, I'm not too sure what sense it makes to show how to implement one with the other (nor that the implementations are actually correct, f.ex. ifCurtailed: block does not trigger on non-local returns...)
Thanks I did not check it carefully enough (argh) it was sent by paolo on a discussion.
Other than that, very nice chapter! Especially liked 1.9 - 1.13, with the thorough explanation of the different ways an exception can be returned from.
Cheers, Henry
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?
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! *yay Henry* *
On Mar 2, 2010, at 9:39 PM, 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
Yes I saw. I was confusing a workspace for the transcript. Start!Start!Finish! here too
|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!
yay Henry _______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
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? Cheers, Balázs & Levente
*yay Henry* *
2010/3/2 Levente Uzonyi <leves@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.
Cheers, Balázs & Levente
*yay Henry* *
-- Best regards, Igor Stasenko AKA sig.
There might be not guarantee that it *can* run the code (an exception might be raised ending the block, it might find itself waiting on an unsignaled semaphore, etc.), but it should be **guaranteed** an opportunity to begin. IIRC, Dolphin provides special handling to temporarily restart processes in order to get this right. Bill -----Original Message----- From: pharo-project-bounces@lists.gforge.inria.fr [mailto:pharo-project-bounces@lists.gforge.inria.fr] On Behalf Of Igor Stasenko Sent: Tuesday, March 02, 2010 4:57 PM To: The general-purpose Squeak developers list Cc: Pharo-project@lists.gforge.inria.fr Subject: Re: [Pharo-project] [squeak-dev] #ensure: issues (was: Re: Pharo by Example vol 2: new chapter available) 2010/3/2 Levente Uzonyi <leves@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.
Cheers, Balázs & Levente
*yay Henry* *
-- Best regards, Igor Stasenko AKA sig. _______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
On Tue, 2 Mar 2010, Igor Stasenko wrote:
2010/3/2 Levente Uzonyi <leves@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. Levente
Cheers, Balázs & Levente
*yay Henry* *
-- Best regards, Igor Stasenko AKA sig. _______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
On Mar 2, 2010, at 10:33 PM, Levente Uzonyi wrote:
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.
Thanks for the explanation levente! But I'm still dizzy :) why Transcript show: 'Finish' would also print 'start' ?
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?
Cheers, Balázs & Levente
*yay Henry* *
On Wed, 3 Mar 2010, Stéphane Ducasse wrote:
On Mar 2, 2010, at 10:33 PM, Levente Uzonyi wrote:
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.
Thanks for the explanation levente! But I'm still dizzy :) why Transcript show: 'Finish' would also print 'start' ?
Transcript is just a stream. #show: is just a combination of #nextPutAll: and #endEntry. #endEntry displays the contents of the stream and when that's done it removes everything from the stream with #resetContents. #resetContents is never executed, because the process is terminated before that. So the contents of the stream are kept and displayed again later. Levente
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?
Cheers, Balázs & Levente
*yay Henry* *
_______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
Thanks Levente! Cheers, Alexandre On 3 Mar 2010, at 11:33, Levente Uzonyi wrote:
On Wed, 3 Mar 2010, Stéphane Ducasse wrote:
On Mar 2, 2010, at 10:33 PM, Levente Uzonyi wrote:
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.
Thanks for the explanation levente! But I'm still dizzy :) why Transcript show: 'Finish' would also print 'start' ?
Transcript is just a stream. #show: is just a combination of #nextPutAll: and #endEntry. #endEntry displays the contents of the stream and when that's done it removes everything from the stream with #resetContents. #resetContents is never executed, because the process is terminated before that. So the contents of the stream are kept and displayed again later.
Levente
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?
Cheers, Balázs & Levente
*yay Henry* *
_______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
_______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
-- _,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;: Alexandre Bergel http://www.bergel.eu ^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;.
Transcript is just a stream. #show: is just a combination of #nextPutAll: and #endEntry. #endEntry displays the contents of the stream and when that's done it removes everything from the stream with #resetContents. #resetContents is never executed, because the process is terminated before that. So the contents of the stream are kept and displayed again later.
I should have looked in the code. Now what is fun is that I did not not get at least an intuition. Anyway I learned something valuable. *Thanks* levente Now what is strange is that we always get this behavior because it relies on the fact that resetContents is not executed so if the process would be suspended a bit later it would be ok. Am'I correct? I will start to write a couple of chapter on concurrent programming because this is the best way to exorcize your doubts. I imagine that I will probably write for newbies and will need some concurrent minded people to catch up what I will write. Stef
FWIW, this quote from the following discussion on Squeak-dev distills what I was trying (but failing) to demonstrate: "We shouldn't stop trying to support well-behaved ensure blocks properly. Because if we don't then ensure becomes entirely random. Or can anyone here explain why it would be reasonable to expect that this version works: p := [[Processor yield] ensure:[Transcript show: 'finished']] fork. Processor yield. p terminate. but this one doesn't: p := [[] ensure:[Processor yield. Transcript show: 'finished']] fork. Processor yield. p terminate. (we're using yield here to denote any kind of process switch) If the only thing that determines whether an ensure block is executed is a process switch, then we basically have random, non-predictable unwind handling. Which is a problem that is entirely unrelated to whether the unwind block is itself well-behaved or not. " In a book with chapters discussing topics such as ensure and processes, (based on Pharo 1.0 which is unlikely to contain any fixes for such an issue), it deserves at least a mention. Cheers, Henry Den 03.03.2010 15:33, skrev Levente Uzonyi:
On Wed, 3 Mar 2010, Stéphane Ducasse wrote:
On Mar 2, 2010, at 10:33 PM, Levente Uzonyi wrote:
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.
Thanks for the explanation levente! But I'm still dizzy :) why Transcript show: 'Finish' would also print 'start' ?
Transcript is just a stream. #show: is just a combination of #nextPutAll: and #endEntry. #endEntry displays the contents of the stream and when that's done it removes everything from the stream with #resetContents. #resetContents is never executed, because the process is terminated before that. So the contents of the stream are kept and displayed again later.
Levente
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?
Cheers, Balázs & Levente
*yay Henry* *
_______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
_______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
btw henrik does VW have the same behavior? Stef On Mar 4, 2010, at 11:38 AM, Henrik Johansen wrote:
FWIW, this quote from the following discussion on Squeak-dev distills what I was trying (but failing) to demonstrate: "We shouldn't stop trying to support well-behaved ensure blocks properly. Because if we don't then ensure becomes entirely random. Or can anyone here explain why it would be reasonable to expect that this version works:
p := [[Processor yield] ensure:[Transcript show: 'finished']] fork. Processor yield. p terminate.
but this one doesn't:
p := [[] ensure:[Processor yield. Transcript show: 'finished']] fork. Processor yield. p terminate.
(we're using yield here to denote any kind of process switch) If the only thing that determines whether an ensure block is executed is a process switch, then we basically have random, non-predictable unwind handling. Which is a problem that is entirely unrelated to whether the unwind block is itself well-behaved or not. "
In a book with chapters discussing topics such as ensure and processes, (based on Pharo 1.0 which is unlikely to contain any fixes for such an issue), it deserves at least a mention.
Cheers, Henry
Den 03.03.2010 15:33, skrev Levente Uzonyi:
On Wed, 3 Mar 2010, Stéphane Ducasse wrote:
On Mar 2, 2010, at 10:33 PM, Levente Uzonyi wrote:
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.
Thanks for the explanation levente! But I'm still dizzy :) why Transcript show: 'Finish' would also print 'start' ?
Transcript is just a stream. #show: is just a combination of #nextPutAll: and #endEntry. #endEntry displays the contents of the stream and when that's done it removes everything from the stream with #resetContents. #resetContents is never executed, because the process is terminated before that. So the contents of the stream are kept and displayed again later.
Levente
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?
Cheers, Balázs & Levente
*yay Henry* *
_______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
_______________________________________________ Pharo-project mailing list
Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
In case anybody is interested, I tried Henrik's example in VAST: | 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!Finish! -- Cheers, Peter On Thu, Mar 4, 2010 at 1:19 PM, Stéphane Ducasse <stephane.ducasse@inria.fr>wrote:
btw henrik
does VW have the same behavior?
Stef
On Mar 4, 2010, at 11:38 AM, Henrik Johansen wrote:
FWIW, this quote from the following discussion on Squeak-dev distills what I was trying (but failing) to demonstrate: "We shouldn't stop trying to support well-behaved ensure blocks properly. Because if we don't then ensure becomes entirely random. Or can anyone here explain why it would be reasonable to expect that this version works:
p := [[Processor yield] ensure:[Transcript show: 'finished']] fork. Processor yield. p terminate.
but this one doesn't:
p := [[] ensure:[Processor yield. Transcript show: 'finished']] fork. Processor yield. p terminate.
(we're using yield here to denote any kind of process switch) If the only thing that determines whether an ensure block is executed is a process switch, then we basically have random, non-predictable unwind handling. Which is a problem that is entirely unrelated to whether the unwind block is itself well-behaved or not. "
In a book with chapters discussing topics such as ensure and processes, (based on Pharo 1.0 which is unlikely to contain any fixes for such an issue), it deserves at least a mention.
Cheers, Henry
Den 03.03.2010 15:33, skrev Levente Uzonyi:
On Wed, 3 Mar 2010, Stéphane Ducasse wrote:
On Mar 2, 2010, at 10:33 PM, Levente Uzonyi wrote:
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.
Thanks for the explanation levente! But I'm still dizzy :) why Transcript show: 'Finish' would also print 'start' ?
Transcript is just a stream. #show: is just a combination of #nextPutAll: and #endEntry. #endEntry displays the contents of the stream and when that's done it removes everything from the stream with #resetContents. #resetContents is never executed, because the process is terminated before that. So the contents of the stream are kept and displayed again later.
Levente
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?
Cheers, Balázs & Levente
*yay Henry* *
_______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
_______________________________________________ Pharo-project mailing list
Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
_______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
Den 04.03.2010 13:19, skrev Stéphane Ducasse:
btw henrik
does VW have the same behavior?
Stef
Short answer is no, Eliot described the details: http://n4.nabble.com/ensure-issues-was-Re-Pharo-project-Pharo-by-Example-vol... Cheers, Henry
On Mar 4, 2010, at 11:38 AM, Henrik Johansen wrote:
FWIW, this quote from the following discussion on Squeak-dev distills what I was trying (but failing) to demonstrate: "We shouldn't stop trying to support well-behaved ensure blocks properly. Because if we don't then ensure becomes entirely random. Or can anyone here explain why it would be reasonable to expect that this version works:
p := [[Processor yield] ensure:[Transcript show: 'finished']] fork. Processor yield. p terminate.
but this one doesn't:
p := [[] ensure:[Processor yield. Transcript show: 'finished']] fork. Processor yield. p terminate.
(we're using yield here to denote any kind of process switch) If the only thing that determines whether an ensure block is executed is a process switch, then we basically have random, non-predictable unwind handling. Which is a problem that is entirely unrelated to whether the unwind block is itself well-behaved or not. "
In a book with chapters discussing topics such as ensure and processes, (based on Pharo 1.0 which is unlikely to contain any fixes for such an issue), it deserves at least a mention.
Cheers, Henry
Den 03.03.2010 15:33, skrev Levente Uzonyi:
On Wed, 3 Mar 2010, Stéphane Ducasse wrote:
On Mar 2, 2010, at 10:33 PM, Levente Uzonyi wrote:
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.
Thanks for the explanation levente! But I'm still dizzy :) why Transcript show: 'Finish' would also print 'start' ?
Transcript is just a stream. #show: is just a combination of #nextPutAll: and #endEntry. #endEntry displays the contents of the stream and when that's done it removes everything from the stream with #resetContents. #resetContents is never executed, because the process is terminated before that. So the contents of the stream are kept and displayed again later.
Levente
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?
Cheers, Balázs & Levente
*yay Henry* *
_______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
_______________________________________________ Pharo-project mailing list
Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
_______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
_______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
Hi Henrik, You're very right. I will fix this this evening. Cheers, Alexandre On 2 Mar 2010, at 16:47, Henrik Sperre Johansen wrote:
On 02.03.2010 14:26, Stéphane Ducasse wrote:
Hi guys
We just released a new chapter for Pharo by Example Vol.2 on Exceptions http://pharobyexample.org/
Let us know what you think.
Stef On p4 there's an error, it says ensure: and ifCurtailed are implemented as primitives, in fact they use the exact same implementation as described of the exception handling in 15.1, the primitive is only used as a marker, and the primitive is required to fail for them to work :) In addition, I'm not too sure what sense it makes to show how to implement one with the other (nor that the implementations are actually correct, f.ex. ifCurtailed: block does not trigger on non-local returns...)
Other than that, very nice chapter! Especially liked 1.9 - 1.13, with the thorough explanation of the different ways an exception can be returned from.
Cheers, Henry
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.
_______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
-- _,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;: Alexandre Bergel http://www.bergel.eu ^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;.
On Mar 2, 2010, at 8:47 PM, Henrik Sperre Johansen wrote:
On 02.03.2010 14:26, Stéphane Ducasse wrote:
Hi guys
We just released a new chapter for Pharo by Example Vol.2 on Exceptions http://pharobyexample.org/
Let us know what you think.
Stef On p4 there's an error, it says ensure: and ifCurtailed are implemented as primitives, in fact they use the exact same implementation as described of the exception handling in 15.1, the primitive is only used as a marker, and the primitive is required to fail for them to work :)
Yes this is more precise
In addition, I'm not too sure what sense it makes to show how to implement one with the other (nor that the implementations are actually correct, f.ex. ifCurtailed: block does not trigger on non-local returns...)
I would be curious to see if your code is working in GNU Smalltalk.
Other than that, very nice chapter! Especially liked 1.9 - 1.13, with the thorough explanation of the different ways an exception can be returned from.
Cheers, Henry
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.
_______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
participants (8)
-
Alexandre Bergel -
Henrik Johansen -
Henrik Sperre Johansen -
Igor Stasenko -
Levente Uzonyi -
Peter Hugosson-Miller -
Schwab,Wilhelm K -
Stéphane Ducasse