Monday, October 19, 2009

Repeat loops, dialog boxes and aborting

It's one of those things that happen to all revolution developers at one point: you have written a repeat loop, inserted some 'answer' dialogs to figure out the problem, only to discover you're stuck and can't abort the loop because the dialog box is in the way. The only way out is killing the process, which has as downside that you've lost all changes to your stack ince the last Save.

After you've been bitten once, you'll probably adopt the habit of inserting an escape plan in your loops. At the same time, you ought to prevent problems in your shipping code with these escape routes, but more on that later - a first escape route may look something like this:

repeat forever
add 1 to theCounter
answer theCounter
-- next block allows escape
if the cantAbort of this stack is false and the shiftKey is down then
answer "Are you sure you want to exit the loop after running" && theCounter && "times?" with "Continue" or "Exit"
if it is "Exit" then exit repeat
end if
end repeat

The cantAbort property of a stack determines whether or not you can abort in the first place (something which you really ought to turn on in standalones) and there's a checkbox on the stack inspector so it's quite convenient.

Another option is to move that block of code into a separate handler at the stack level

on CheckForAbort pCounter
if the cantAbort of this stack is false and the shiftKey is down then
answer "Are you sure you want to abort execution of" && pInfo && "?" with "Continue" or "Exit"
if it is "Exit" then exit to top
end if
end CheckForAbort

and then add a call to that handler in your loop

repeat forever
add 1 to theCounter
answer theCounter
CheckForAbort "TightLoop-" & theCounter
end repeat

The downside of the second approach is that any cleanup code that comes after the repeat won't be called. Of course you can also rely on try-throw-catch exception handling, but some people find this awkward.

So just for completion, here's how you'd allow escape with cleanup via exception handling; first change the CheckForAbort handler to

on CheckForAbort pInfo
if the cantAbort of this stack is false and the shiftKey is down then
answer "Are you sure you want to abort execution of" && pInfo && "?" with "Continue" or "Exit"
if it is "Exit" then throw "Aborting execution of" && pInfo
end if
end CheckForAbort

and then modify the script with the loop so that it resembles the following

try
repeat forever
add 1 to theCounter
answer theCounter
CheckForAbort "TightLoop-" & theCounter
end repeat
catch tError
answer error tError
finally
-- do your cleanup here
--> it will be called whether or not something throws an error
end try

Hopefully, this will be of use to you at one point or another. Make sure to check out these entries in the documentation for more information about aborting running scripts: cantAbort stack property, allowInterrupts global property, interrupt function and of course the try-throw-catch triade for exception handling. Use them wisely, and provide your users with a safer envronment to work in...

No comments: