CONTENTS | PREV | NEXT
13B. using the Raise() function
-------------------------------
There are many ways to actually "raise" an exception, the simplest
is through the function Raise():
Raise(exceptionID=0)
the exception ID is simply a constant that defines the type of
exception, and is used by handlers to determine what went wrong.
Example:
ENUM NOMEM,NOFILE /* and others */
PROC bla() HANDLE
DEF mem
IF (mem:=New(10))=NIL THEN Raise(NOMEM)
myfunc()
EXCEPT
SELECT exception
CASE NOMEM
WriteF('No memory!\n')
/* ... and others */
ENDSELECT
ENDPROC
PROC myfunc()
DEF mem
IF (mem:=New(10))=NIL THEN Raise(NOMEM)
ENDPROC
The "exception" variable in the handler always contains the value of
the argument to the Raise() call that invoked it.
In both New() cases, the Raise() function invokes the handler of
function bla(), and then exits it correctly to the caller of bla().
If myfunc() had its own exception-handler, that one would be invoked
for the New() call in myfunc(). The scope of a handler is from the start
of the PROC in which it is defined until the EXCEPT keyword, including
all calls made from there.
This has three consequences:
A. handlers are organized in a recursive fashion, and which handler is
actually invoked is dependant on which function calls which at runtime;
B. if an exception is raised within a handler, the handler of a lower
level is invoked. This characteristic of handlers may be used
to implement complex recursive resource allocation schemes with
great ease, as we'll see shortly.
C. If an exception is raised on a level where no lower-level handler
is available (or in a program that hasn't got any handlers at all),
the program is terminated. (i.e: Raise(x) has the same effect as
CleanUp(0))
other functions:
Throw(exceptionID,value)
same as Raise(), only now it takes an arbitrary value with it. in
a handler one can then scrutinize this value with the variable
'exceptioninfo'
ReThrow()
has no args. simply does a Throw() on the current exception value,
IFF it is <>0.