<div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div>Hi all,</div><div>when writing scripts, I often need the ability to interrupt a loop.</div><div>This is the traditional break instruction of C/Python or more advanced exit of FORTRAN/ADA (we can tell from which nexted loop we exit).<br></div><div dir="ltr"><br></div><div>I could use exceptions, but then handling exit from nested loops is tricky (see below).</div><div>One possible way to do it in Smalltalk is to use blocks, and interrupt with non local return.</div><div><div><br></div><div>ref <a href="http://lists.gnu.org/archive/html/help-smalltalk/2008-06/msg00077.html">http://lists.gnu.org/archive/html/help-smalltalk/2008-06/msg00077.html</a></div></div><div><br></div><div dir="ltr">Object>>escape: aBlock<br>    "Give the ability to exit execution of aBlock by returning control to sender.</div><div>    aBlock will take an argument, which is a door for returning control.<br></div><div dir="ltr">    This is useful for breaking a loop, for example:<br>     self escape: [:exit | someCollection do: [:e | e fullfilSomeCondition ifTrue: [exit value]. e doSometing]]"<br>    aBlock value: [^self]</div><div dir="ltr"><br></div><div>| sum |</div><div>sum := 0.<br></div><div>self escape: [:exitOuterLoop | someCollection do: [:e |</div><div>    self escape: [:exitInnerLoop | someOtherCollection do: [:e2 |</div><div>        e2 > e ifTrue: [exitOuterLoop value].</div><div>        e2 = e ifTrue: [exitInnerLoop value].</div><div>        sum := sum + e]]]].</div><div>^sum</div><div><br></div><div>We can also use the escape: inside the loop to avoid chained ifTrue:ifFalse:</div><div><div>but it's then convenient to let escape: return a value:</div><div><br></div><div><div dir="ltr">Object>>escape: aBlock<br>    ^aBlock value: [:result | ^result]</div><div dir="ltr"><br></div></div></div><div>aCollection collect: [:e |</div><div>    e escape: [:return |</div><div>        e < 0 ifTrue: [return value: e].<br><div>        e > 20 ifTrue: [return value: 401 ln].</div><div>       (e squared + 1) ln]]<br></div></div><div><br></div><div>ref <a href="https://stackoverflow.com/questions/7547750/smalltalk-block-can-i-explicitly-set-the-returning-value-and-stop-executing-th/11532045#11532045">https://stackoverflow.com/questions/7547750/smalltalk-block-can-i-explicitly-set-the-returning-value-and-stop-executing-th/11532045#11532045</a></div><br><div>At that time, I found that amusing, now I find it useful.<br></div><div>I don't see such support in trunk image, could we add it?</div><div>Do you think of a better name?</div><div>(not setjmp: please)</div><div><br></div>Unless you come with better alternatives... One thing that is questionable is that the receiver of escape: is void (escape: is a utility).</div><div dir="ltr"><br></div><div>There is <a href="https://stackoverflow.com/questions/52683795/gnu-smalltalk-break-from-whiletrue-loop-without-return/52702174#52702174">https://stackoverflow.com/questions/52683795/gnu-smalltalk-break-from-whiletrue-loop-without-return/52702174#52702174</a> <br></div><div>It start looking like FORTRAN/ADA exit instruction with explicit naming of loop but I don't like it better.<br></div><div><br></div><div>Maybe sending the message to the block itself sounds less arbitrary.</div><div><br></div><div>BlockClosure>>handleExit</div><div>    ^self value: [:result | ^result]</div><div><br></div><div><div>| sum |</div><div>sum := 0.<br></div><div>[:exitOuterLoop | someCollection do: [:e |</div><div>     [:exitInnerLoop | someOtherCollection do: [:e2 |</div><div>        e2 > e ifTrue: [exitOuterLoop value: nil].</div><div>        e2 = e ifTrue: [exitInnerLoop value: nil].</div><div>        sum := sum + e]] handleExit ]] handleExit.</div><div>^sum</div></div><div dir="ltr"><div><br></div><div>Though, I don't find such post-fixing satisfactory: exitOuterLoop and handleExit are too far from each other... Especially in scripts that tend to be longer than ordinary methods (we don't want to factor every quick and dirty procedure into proper classes/methods when there is no reuse objective or when they are too specific).<br></div></div></div></div></div>