Since REXX may abort your script abruptly at any line if a SYNTAX or HALT condition happens, it is possible that your script has not been given a chance to do something that needs to do before it terminates.

The FINALLY instruction allows you to specify a group of instructions to always be executed when your script ends. This is very handy for any cleanup or final operation you need to do. The FINALLY instructions are automatically executed, even if your script aborts due to some HALT, SYNTAX, (or USER) condition (that you don't handle yourself), or if your script simply does a RETURN/EXIT. If you need to free/close/etc anything at the end of your script, you'll find the FINALLY instruction to be quite useful for that purpose.

For example, assume you obtained some "handle" from the operating system. You need to free it when your script ends. This needs to be done whether your script ends normally with a RETURN instruction, or if it bombs out due to SYNTAX or HALT. What you'll do is put a FINALLY instruction at the end of your script. Then, you put your cleanup instructions after it.

Note: The FINALLY (and its instructions) must be at the very bottom of your script, after all other subroutines and anything else. Don't put a colon after FINALLY. It's not a label. It's an instruction.

Here we call the function FreeHandle() to free the handle (if it was ever obtained - we check that with the EXISTS function):

/* Here we get some handle. */
MyHandle = GetAHandle()

/* Here we would use the handle. If something goes
 * wrong and our script bombs out, FINALLY gets
 * done.
 */

/* Now assume that our script is done. We simply do a
 * RETURN. Reginald will automatically do all of the
 * instructions after the FINALLY. We don't have to
 * explicitly jump there ourselves.
 */
RETURN

/* Here are the instructions that always get done,
 * whether we did a normal RETURN to end our script,
 * or if it bombed out due to SYNTAX or HALT that we
 * didn't handle ourselves.
 */
FINALLY
   IF EXISTS('MyHandle') THEN FreeHandle(MyHandle)

FINALLY inbetween DO and END

Every DO/END can have its own FINALLY set of instructions. You put the FINALLY (and its instructions) immediately before the END.

Assume that we want to call some subroutine named DoSomething. In DoSomething, we get another handle from the operating system, but we want to make sure that we free this handle when DoSomething ends. (We don't want to wait until our script ends. We need that handle only inside of DoSomething). We will put a DO/END inside of DoSomething, and then put some more FINALLY instructions there, as so:

MyHandle = GetAHandle()
/* Let DoSomething get some handle and perform work on it. */
DoSomething()
RETURN


DoSomething:
   /* Let's put a DO/END, with a FINALLY inside of it.
    * These FINALLY instructions will get done when this
    * DO END finishes, even if it is interrupted by a
    * condition such as SYNTAX or HALT, etc.
    */
   DO
      MyOtherHandle = GetAHandle()

      /* Do something with MyOtherHandle. Note that
       * the FINALLY will always get done no matter
       * how this DO/END finishes, so that's where we
       * make sure that MyOtherHandle is freed.
       */

      FINALLY
         IF EXISTS('MyOtherHandle') THEN FreeHandle(MyOtherHandle)
         RETURN
   END

FINALLY
   IF EXISTS('MyHandle') THEN FreeHandle(MyHandle)
So what happens if a SYNTAX error happens inside of DoSomething? Notice above that I'm not expliciting handling SYNTAX in any way. So my script is going to end. But, before it ends, those FINALLY instructions inside of DoSomething will be done, and then the FINALLY instructions at the end of the script will be done. So there it is -- automatic cleanup.

If no SYNTAX condition happens, then those FINALLY instructions will still get done at the end of the DO/END. Note that we put no RETURN statement at the end of DoSomething. Our FINALLY has a RETURN statement, and it always gets done, so we never do drop out of that DO/END. We always RETURN from it.

FINALLY can be used inside of any type of DO/END. For example, here I count from 1 to 5. When count reaches 5, my loop ends, and the FINALLY instructions always get done then. (They do not get executed until the loop ends. In other words, they don't get executed each time through the loop).

DO count = 1 TO 5
   SAY count

   /* Here are the instructions that always get done
    * when this loop ends, whether "count" reaches 5,
    * or we do a LEAVE or RETURN or EXIT, or some
    * condition happens such as SYNTAX or HALT, etc.
    */
   FINALLY
      SAY "This loop has ended"
END
SAY "Continuing..."
Note that we have no RETURN instruction in our FINALLY, so after FINALLY is done, then the loop ends and we drop down to display Continuing....


Errata

As you can see, the FINALLY instruction can greatly simplify and bulletproof your cleanup code, without any need for SIGNAL statements and labels.

Warning: Using a SIGNAL statement to jump somewhere will defeat any FINALLY instructions you have set up. For this reason, you should avoid using any SIGNAL statements unless you do not place them inside of any DO/END that has a FINALLY, nor use any SIGNAL in your FINALLY instructions.