Raisewithin an Exception Handler
If you call
Raise within an exception handler then control passes to the next most recent handler.
In this way you can write procedures which have handlers that perform local tidying up.
Raise at the end of the handler code you can invoke the next layer of tidying up.
As an example we'll use the Amiga system functions
FreeMem which are like the built-in function
Dispose, but the memory allocated by
AllocMem must be deallocated (using
FreeMem) when it's finished with, before the end of the program.
CONST SMALL=100, BIG=123456789 ENUM ERR_MEM=1 RAISE ERR_MEM IF AllocMem()=NIL PROC main() allocate() ENDPROC PROC allocate() HANDLE DEF mem=NIL mem:=AllocMem(SMALL, 0) morealloc() FreeMem(mem, SMALL) EXCEPT IF mem THEN FreeMem(mem, SMALL) WriteF('Handler: deallocating "allocate" local memory\n') ENDPROC PROC morealloc() HANDLE DEF more=NIL, andmore=NIL more:=AllocMem(SMALL, 0) andmore:=AllocMem(BIG, 0) WriteF('Allocated all the memory!\n') FreeMem(andmore, BIG) FreeMem(more, SMALL) EXCEPT IF andmore THEN FreeMem(andmore, BIG) IF more THEN FreeMem(more, SMALL) WriteF('Handler: deallocating "morealloc" local memory\n') Raise(ERR_MEM) ENDPROC
The calls to
AllocMem are automatically checked, and if
NIL is returned the exception
ERR_MEM is raised.
The handler in the
allocate procedure checks to see if it needs to free the memory pointed to by
mem, and the handler in the
At the end of the
morealloc handler is the call
This passes control to the exception handler of the
allocate procedure, since
There's a couple of subtle points to notice about this example.
Firstly, the memory variables are all initialised to
This is because the automatic exception raising on
AllocMem will result in the variables not being assigned if the call returns
NIL (i.e., the exception is raised before the assignment takes place), and the handler needs them to be
Of course, if
AllocMem does not return
NIL the assignments work as normal.
IF statements in the handlers check the memory pointer variables do not contain
NIL by using their values as truth values.
NIL is actually zero, a non-
NIL pointer will be non-zero, i.e., true in the
This shorthand is often used, and so you should be aware of it.
It is quite common that an exception handler will want to raise the same exception after it has done its processing.
ReThrow (which has no arguments) can be used for this purpose.
It will re-raise the exception, but only if the exception is not zero (since this special value means that no error occurred).
If the exception is zero then this function has no effect.
In fact, the following code fragments (within a handler) are equivalent:
ReThrow() IF exception THEN Throw(exception, exceptioninfo)
There are two examples, in Part Three, of how to use an exception handler to make a program more readable: one deals with using data files (see 19 String Handling and I/O) and the other deals with opening screens and windows (see 22.4 Screens).
Go to the Next or Previous section, the Detailed Contents, or the Amiga E Encyclopedia.