Go to the Next or Previous section, the Detailed Contents, or the Amiga E Encyclopedia.


13.4 Raise within 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. By using 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 AllocMem and FreeMem which are like the built-in function New and 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 morealloc checks andmore and more. At the end of the morealloc handler is the call Raise(ERR_MEM). This passes control to the exception handler of the allocate procedure, since allocate called morealloc.

There's a couple of subtle points to notice about this example. Firstly, the memory variables are all initialised to NIL. 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 NIL if AllocMem fails. Of course, if AllocMem does not return NIL the assignments work as normal.

Secondly, the IF statements in the handlers check the memory pointer variables do not contain NIL by using their values as truth values. Since NIL is actually zero, a non-NIL pointer will be non-zero, i.e., true in the IF check. 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. The function 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.