<html><head>
<title></title>
<style id="css_styles" type="text/css"><!--blockquote.cite { margin-left: 5px; margin-right: 0px; padding-left: 10px; padding-right:0px; border-left: 1px solid #cccccc }
blockquote.cite2 {margin-left: 5px; margin-right: 0px; padding-left: 10px; padding-right:0px; border-left: 1px solid #cccccc; margin-top: 3px; padding-top: 0px; }
a img { border: 0px; }
li[style='text-align: center;'], li[style='text-align: center; '], li[style='text-align: right;'], li[style='text-align: right; '] { list-style-position: inside;}
body { font-family: 'Segoe UI'; font-size: 12pt; }
.quote { margin-left: 1em; margin-right: 1em; border-left: 5px #ebebeb solid; padding-left: 0.3em; }
a.em-mention[href] { text-decoration: none; color: inherit; border-radius: 3px; padding-left: 2px; padding-right: 2px; background-color: #e2e2e2; }
._em_placeholder {color: gray; border-bottom: 1px dotted lightblue;} ._em_placeholder:before{color:gray; content: '{{ ';} ._em_placeholder:after{color:gray; content: ' }}';}
--></style></head>
<body style="background-color: white; color: black;"><div style="">Hi Juan,
</div><div style="">
</div><div style="">I've just come across a situation brought up by Christoph Thiede where your example/reasoning might apply - or maybe not. Please help :)
</div><div style="">
</div><div style="">Consider a simple example:
</div><div style="">
</div><div style="">[^1] ensure: [^42]
</div><div style="">
</div><div style="">What would you expect to be the return value of the expression?
</div><div style="">
</div><div style="">There seem to be three candidates: 1, or 42, or undefined. The reason for considering undefined comes from the ANSI specification (draft 1997):
</div><div style="">
</div><div style="">"If the evaluation of a termination block concludes with the execution of a return statement the result is undefined. The
</div><div style="">result is also undefined if evaluation of the termination block results in evaluation of any block that concludes with a return statement and whose home activation is not on the call chain that starts with the activation of the termination block." (paragraph 3.4.5.1, page 22)
</div><div style="">
</div><div style="">If I'm reading this correctly the authors didn't approve of jumping over the #ensure: argument block activation using a non-local return from the #ensure: argument block (aka terminationBlock). Hence declaring such an act undefined.
</div><div style="">
</div><div style="">Returning any value from such an expression would then be an extension of the ANSI specification, I guess.
</div><div style="">
</div><div style="">Now, if I use your reasoning and modify your example from your mail below, I get this:
</div><div style="">
</div><div style="">m2: a "A"
</div><div style=""> [1 + 2] ensure: [
</div><div style=""> true ifTrue: [
</div><div style=""> [ ^3 + 4 ] ensure: [ "*1"
</div><div style=""> true ifTrue: [
</div><div style=""> ^a at: 1 put: true ]]. "*2"
</div><div style=""> a at: 2 put: true ]]
</div><div style="">
</div><div style="">
</div><div style="">m2: a "B"
</div><div style=""> [1 + 2] ensure: [
</div><div style=""> true ifTrue: [
</div><div style=""> res_inner := 3 + 4.
</div><div style=""> true ifTrue: [
</div><div style=""> ^a at: 1 put: true ].
</div><div style=""> a at: 2 put: true.
</div><div style=""> ^res_inner]]
</div><div style="">
</div><div style="">
</div><div style="">m2: a "C"
</div><div style=""> res_outer := 1 + 2.
</div><div style=""> true ifTrue: [
</div><div style=""> res_inner := 3 + 4.
</div><div style=""> true ifTrue: [
</div><div style=""> ^a at: 1 put: true ].
</div><div style=""> a at: 2 put: true.
</div><div style=""> ^res_inner].
</div><div style=""> ^res_outer
</div><div style="">
</div><div style="">
</div><div style="">Would this be a correct and appropriate application of your example and reasoning on this situation?
Would you expect true to be returned from m2?</div><div style="">
</div><div style="">In this case you'd allow jumping over the activation of the terminationBlock from the terminationBlock and the expression `[^1] ensure: [^42]` would return 42. However, the semantics used in the unwind algorithm during termination is the opposite - it won't let the non-local return from the terminationBlock escape/jump over the #ensure: activation - which would result in the expression `[^1] ensure: [^42]` returning 1. </div><div style="">
</div><div style="">Funny thing is in Squeak I've unified the unwind logic for termination and general returns, so Squeak returns 1, but in Cuis we kept the previous unwind logic in #return:through: and as a result Cuis returns 42 :)
</div><div style="">
</div><div style="">I'm aware it's rather "academic" and not very useful in 99.9% of situations but I'd be very interested in your opinion if you could spare a few moments out of your busy schedule.
</div><div style="">
</div><div style="">Thanks a lot!
</div><div style="">
</div><div style="">Best regards,
</div><div style="">Jaromir
</div><div style="">
</div><div style=""><br /></div><div style="">PS: Christoph's original example was:
</div><div style="">
</div><div style="">Object compile: 'sample
</div><div style=""> [[^1] ensure: [Transcript showln: #hi. self error]]
</div><div style=""> on: Error do: [:ex | ^ ex]'.
</div><div style="">self sample
</div><div style="">
</div><div style="">but I think my simplification captures the same idea...</div>
<div style=""><br style="" /></div>
<div x-em-replyforwardheader="" style=""><br style="" /></div>
<div style="">
<div style="">On 30-Apr-21 7:31:54 PM, "Juan Vuletich via Cuis-dev" <<a href="mailto:cuis-dev@lists.cuis.st" style="">cuis-dev@lists.cuis.st</a>> wrote:</div></div><div x-em-quote="" style=""><br style="" /></div>
<div id="xaca0517ad2874af" style="color: rgb(0, 0, 0);"><blockquote cite="608C3F0A.2090404@jvuletich.org" type="cite" class="cite2" style="">
Hi Jaromir,<br style="" /><o:p xmlns:o="#unknown" style=""><br style="" />
</o:p>
<blockquote cite="mid:BN7PR08MB38422AE118D7EADA80DE7127EE5E9@BN7PR08MB3842.namprd08.prod.outlook.com" type="cite" class="cite" style="">
<div class="WordSection1" style="">
<p class="MsoNormal" style="">I’ve tried to rewrite your #test1ATerminate
without the method calls – and indeed it passes… and
that’s why I missed that – it was too simple; when using sends
is where your fix comes to the rescue – THANKS!
</p>
<p class="MsoNormal" style=""><o:p xmlns:o="#unknown" style=""> </o:p></p>
<p class="MsoNormal" style=""> | p a |</p>
<p class="MsoNormal" style=""> a := Array new: 4 withAll: false.</p>
<p class="MsoNormal" style=""> p := [</p>
<p class="MsoNormal" style=""> [</p>
<p class="MsoNormal" style=""> [ ] ensure: [</p>
<p class="MsoNormal" style="">
[Processor activeProcess
suspend] ensure: [
</p>
<p class="MsoNormal" style="">
^a at: 1 put:
true]. "line L1"
</p>
<p class="MsoNormal" style="">
a at: 2 put:
true] "line L2"
</p>
<p class="MsoNormal" style=""> ] ensure: [a
at: 3 put: true].
</p>
<p class="MsoNormal" style=""> a at: 4 put:
true
</p>
<p class="MsoNormal" style=""> ] newProcess.</p>
<p class="MsoNormal" style=""> p resume.</p>
<p class="MsoNormal" style=""> Processor yield.</p>
<p class="MsoNormal" style=""> "make sure p is suspended and none of
the unwind blocks has finished yet"
</p>
<p class="MsoNormal" style=""> self assert: p isSuspended.</p>
<p class="MsoNormal" style=""> a noneSatisfy: [ :b | b ].</p>
<p class="MsoNormal" style=""> "now terminate the process and make
sure all unwind blocks have finished"
</p>
<p class="MsoNormal" style=""> p terminate.</p>
<p class="MsoNormal" style=""> self assert: p isTerminated.</p>
<p class="MsoNormal" style=""> self assert: a first & a third.</p>
<p class="MsoNormal" style=""> self assert: (a second | a fourth) not.</p>
</div>
</blockquote>
<br style="" />
Yes it does. I just thought that a more real-life like test of non
local returns should also include actual method calls!
<br style="" />
<blockquote cite="mid:BN7PR08MB38422AE118D7EADA80DE7127EE5E9@BN7PR08MB3842.namprd08.prod.outlook.com" type="cite" class="cite" style="">
<div class="WordSection1" style="">
<p class="MsoNormal" style="">I’d like to raise a question here: I feel
the second item, on line L2 should ideally execute too because
it’s inside an unwind block halfway through it’s termination.
The problem is though the non-local return at line L1 invokes
it’s own unwind algorithm in #resume:through: which ignores
halfway through unwind blocks – the reason for that is
#resume:through: operates on the active process’s stack which
makes it extremely difficult to unwind halfway through blocks.
I tried to apply a similar tactics like in termination
(control the unwind from another stack) and it works well but
it’s very intrusive… I may open a separate discussion on that
later to share the results. Do you think it may be worth
exploring or it’s just not worth the bother?
</p>
</div>
</blockquote>
<o:p xmlns:o="#unknown" style=""><br style="" />
Well. This is not just in the case of process #terminate, right?
To play with this without involving process handling, but
including actual method calls I just tried this:
<br style="" />
<br style="" />
m1<br style="" />
| a |<br style="" />
a := Array new: 3.<br style="" />
self m2: a.<br style="" />
a at: 3 put: true.<br style="" />
a print.<br style="" />
<br style="" />
m2: a "A"<br style="" />
[1 + 2] ensure: [<br style="" />
[ 3 + 4 ] ensure: [ "*1"<br style="" />
true ifTrue: [<br style="" />
^a at: 1 put: true ]]. "*2"<br style="" />
a at: 2 put: true ]<br style="" />
<br style="" />
In this example, the *1ensure is there only to guarantee that *2is
ran, even if [3+4] happens to fail. If [3+4] it runs without
problems, the result should be exactly the same as
</o:p>:<br style="" />
<br style="" />
m2: a "B"<br style="" />
[1 + 2] ensure: [<br style="" />
3 + 4.<br style="" />
true ifTrue: [<br style="" />
^a at: 1 put: true ].<br style="" />
a at: 2 put: true ]<br style="" />
<br style="" />
Applying the same argument, the result should be the same as:<br style="" />
<br style="" />
m2: a "C"<br style="" />
1 + 2.<br style="" />
3 + 4.<br style="" />
true ifTrue: [<br style="" />
^a at: 1 put: true ].<br style="" />
a at: 2 put: true<br style="" />
<br style="" />
In implementation C it is clear that a second isNil. So, the same
should be the case for B and A.
<br style="" />
<br style="" />
I think that an ensured block should be guaranteed to run without
external interference. But if it decides on its own to exit before
running all its statements, it is it's own decision.
<br style="" />
<o:p xmlns:o="#unknown" style=""><br style="" />
</o:p>
<blockquote cite="mid:BN7PR08MB38422AE118D7EADA80DE7127EE5E9@BN7PR08MB3842.namprd08.prod.outlook.com" type="cite" class="cite" style="">
<div class="WordSection1" style="">
<p class="MsoNormal" style="">Another issue: I considered using the error
part of the result of #runUntilErrorOrReturnFrom: to deal with
situations like this (careful – crashes the Cuis image without
the terminate fix; with the fix it works “ok”):
</p>
<p class="MsoNormal" style=""><o:p xmlns:o="#unknown" style=""> </o:p></p>
<p class="MsoNormal" style="">x := nil.</p>
<p class="MsoNormal" style="">[self error: 'x1'] ensure: [</p>
<p class="MsoNormal" style=""> [self error: 'x2'] ensure: [</p>
<p class="MsoNormal" style=""> [self error: 'x3'] ensure: [</p>
<p class="MsoNormal" style=""> x:=3].</p>
<p class="MsoNormal" style=""> x:=2].</p>
<p class="MsoNormal" style=""> x:=1].</p>
<p class="MsoNormal" style="">x</p>
<p class="MsoNormal" style=""><o:p xmlns:o="#unknown" style=""> </o:p></p>
<p class="MsoNormal" style="">Here you have nested errors and the
question is: If we abandon the Debugger window, what do we
want to see as a result? Without the fix the image crashes
badly with unwind errors, with the fix however the Debugger
closes without unwinding – it’s a consequence of #
runUntilErrorOrReturnFrom: behavior – it returns errors rather
than opens a debugger (and leaves the decision with the user).
So what do we want to see as a result – keep opening debugger
windows and abandoning them manually or ignoring the errors
and executing the assignments? That sounds like “resuming”
rather than abandoning to me so at the moment I don’t know and
will have to think about it. I just didn’t want to complicate
the #terminate prematurely :)
</p>
</div>
</blockquote>
<o:p xmlns:o="#unknown" style=""><br style="" />
I think this case is very similar to the one above.. For example,
if we proceed the first debugger (the x1 error), the x2 debugger
opens. If we abandon it, we are abandoning the execution of the
first ensured block (that includes the x := 1 assignment at the
end). So, no assignment is done. I think that the behavior of our
fix is correct in this case. No need to simulate "resuming".
<br style="" />
<br style="" />
</o:p>
<blockquote cite="mid:BN7PR08MB38422AE118D7EADA80DE7127EE5E9@BN7PR08MB3842.namprd08.prod.outlook.com" type="cite" class="cite" style="">
<div class="WordSection1" style="">
<p class="MsoNormal" style="">Juan, many thanks again, I’ll study your
tests and learn from them.
</p>
</div>
</blockquote>
<br style="" />
I'm happy to be of help. There's not nothing in those tests that
could be new to you. All I did was to add nested method calls, and
add the #resume cases, that already did work with the fix. Let me
thank you. You did a great analysis of the issues at hand, and your
fix is a great contribution.
<br style="" />
<br style="" />
I'll integrate it right now. If any further analysis provides
additional changes, we'll integrate them too.
<br style="" />
<o:p xmlns:o="#unknown" style=""><br style="" />
</o:p>
<blockquote cite="mid:BN7PR08MB38422AE118D7EADA80DE7127EE5E9@BN7PR08MB3842.namprd08.prod.outlook.com" type="cite" class="cite" style="">
<div class="WordSection1" style="">
<p class="MsoNormal" style="">Best regards,</p>
<p class="MsoNormal" style=""><o:p xmlns:o="#unknown" style=""> </o:p></p>
<p class="MsoNormal" style="">jaromir</p>
<p class="MsoNormal" style=""><o:p xmlns:o="#unknown" style=""> </o:p></p>
</div>
</blockquote>
<br style="" />
Cheers,<br style="" />
<pre class="moz-signature" cols="72" style="">--
Juan Vuletich
<a class="moz-txt-link-abbreviated" href="http://www.cuis-smalltalk.org" style="">www.cuis-smalltalk.org</a>
<a class="moz-txt-link-freetext" href="https://github.com/Cuis-Smalltalk/Cuis-Smalltalk-Dev" style="">https://github.com/Cuis-Smalltalk/Cuis-Smalltalk-Dev</a>
<a class="moz-txt-link-freetext" href="https://github.com/jvuletich" style="">https://github.com/jvuletich</a>
<a class="moz-txt-link-freetext" href="https://www.linkedin.com/in/juan-vuletich-75611b3" style="">https://www.linkedin.com/in/juan-vuletich-75611b3</a>
@JuanVuletich</pre>
</blockquote></div>
<style type="text/css" style=""><!--#xaca0517ad2874af p.MsoNormal, #xaca0517ad2874af li.MsoNormal, #xaca0517ad2874af div.MsoNormal
{margin: 0in; font-size: 11pt; font-family: Calibri, sans-serif; color: windowtext;}
#xaca0517ad2874af h1
{margin-right: 0in; margin-left: 0in; font-size: 24pt; font-family: Calibri, sans-serif; color: black; font-weight: bold;}
#xaca0517ad2874af h2
{margin-right: 0in; margin-left: 0in; font-size: 18pt; font-family: Calibri, sans-serif; color: black; font-weight: bold;}
#xaca0517ad2874af a:link, #xaca0517ad2874af span.MsoHyperlink
{color: blue; text-decoration: underline;}
#xaca0517ad2874af pre
{margin: 0in; font-size: 10pt; font-family: "Courier New"; color: black;}
#xaca0517ad2874af span.Heading1Char, #xaca0517ad2874af span.Heading2Char
{font-family: Calibri, sans-serif; color: black; font-weight: bold;}
#xaca0517ad2874af span.HTMLPreformattedChar
{font-family: "Courier New"; color: black;}
#xaca0517ad2874af .MsoChpDefault
{}
#xaca0517ad2874af div.WordSection1
{page: WordSection1;}
--></style></body></html>