Exceptions
Exceptional conditions, including errors, in NetRexx are handled by a mechanism called Exceptions. When an exceptional condition occurs, a signal takes place which may optionally be caught by an enclosing control construct, as detailed below.
An exception can be signalled by:
- the program's environment, when some processing error occurs (such as running out of memory, or a problem discovered when reading or writing a file)
- a method called by a NetRexx program (if, for example, it is passed incorrect arguments)
- the signal instruction.
In all cases, the signal is handled in exactly the same way. First, execution of the current clause ceases; no further operations within the clause will be carried out.[1] Next, an object that represents the exception is constructed. The type of the exception object is implementation-dependent, as described for the signal instruction, and defines the type of the exception. The object constructed usually contains information about the Exception (such as a descriptive string).
Once the object has been constructed, all active do groups, loop loops, if constructs, and select constructs in the active method are 'unwound', starting with the innermost, until the exception is caught by a control construct that specifies a suitable catch clause (see below) for handling the exception.
This unwinding takes place as follows:
- No further clauses within the body of the construct will be executed (in this respect, the signal acts like a leave for the construct).
- If a catch clause specifies a type to which the exception object can be assigned (that is, it matches or is a superclass of the type of exception object), then the instructionlist following that clause is executed, and the exception is considered to be handled (no further control constructs will be unwound). If more than one catch clause specifies a suitable type, the first is used.
- The instructionlist following the finally clause for the construct, if any, is executed.
- The end clause is executed, hence completing execution of the construct. (The only effect of this is that it is seen when tracing.)
- If the exception was handled, then execution resumes as though the construct completed normally. If it was not handled, then the process is repeated for any enclosing constructs.
If the exception is not caught by any of the control constructs enclosing the original point of the exception signal, then the current active method is terminated, without returning any data, and the exception is then signalled at the point where the method was invoked (that is, in the caller).
The process of unwinding control constructs and terminating the method is then repeated in each calling method until the exception is caught or the initial program invocation method (the main method) is terminated, in which case the program ends and the environment receives the signal (it would usually then display diagnostic information).
Syntax and example
The constructs that may be used to handle (catch) an exception are do groups, loop loops, and select constructs. Specifically, as shown in the syntax diagrams (q.v.), where the end clause can appear in these constructs, zero or more catch clauses can be used to define exception handlers, followed by zero or one finally clauses that describe 'clean-up' code for the construct. The whole construct continues to be ended by an end clause.
The syntax of a catch clause is shown in the syntax diagrams. It always specifies an exception type, which may be qualified. It may optionally specify a symbol, vare, which is followed by an equals sign. This indicates that when the exception is caught then the object representing the exception will be assigned to the variable vare. If new, the type of the variable will be exception.
Here is an example of a program that handles some of the exceptions signalled by methods in the Rexx class; the trace results instruction is included to show the flow of execution:
trace results
do -- could be LOOP i=1 to 10, etc.
say 1/arg
catch DivideException
say 'Divide exception'
catch ex=NumberFormatException
/* 'ex' is assigned the exception object */
say 'Bad number for division:' ex.getMessage
finally
say 'Done!'
end
In this example, if the argument passed to the program (and hence placed in arg) is a valid number, then its inverse is displayed. If the argument is 0, then 'Divide exception' would be displayed. If the argument were an invalid number, the message describing the bad number would be displayed. For any other exception (such as an ExponentOverflowException), the program would end and the environment would normally report the exception.
In all cases, the message 'Done!' would be displayed; this would be true even if the body of the do construct executed a return, leave, or iterate instruction. Only an exit instruction would cause immediate termination of the construct (and the program).
Note: The finally keyword, like otherwise in the select construct, implies a semicolon after it, so the last say instruction in the example could have appeared on the same line as the finally without an intervening semicolon.
Exceptions after catch and finally clauses
If an exception is signalled in the instructionlist following a catch or finally clause, then the current exception is considered handled, the instructionlist is terminated, and the new exception is signalled. It will not be caught by catch clauses in the current construct. If it occurs in the instructionlist following a catch clause, then any finally instructions will be executed, as usual.
Similarly, executing a return or exit instruction within either of the instructionlists completes the handling of any pending signal.
Checked exceptions
NetRexx implementations may define certain exceptions as checked exceptions. These are exceptions that the implementation considers it useful to check; the checked exceptions that each method may signal are recorded. Within do groups, loop loops, and select constructs, for example, it is then possible to report if a catch clause tries to catch a checked exception that is not signalled within the body of the construct.
Checked exceptions that are signalled within a method (by a signal instruction or a method invocation) but not caught by a catch clause in the method are automatically added to the signals list for a method. Implementations that support checked exceptions are encouraged to provide options that list the uncaught checked exceptions for methods or enforce the explicit inclusion of some or all checked exceptions in the signals list on the method instruction.
In the reference implementation, all exceptions are checked except those that are subclasses of
java.lang.RuntimeException or
java.lang.Error. These latter are considered so ubiquitous that almost all methods would signal them.
Expressions assigned as the initial values of properties must not invoke methods that may signal checked exceptions.
The strictsignal option on the options instruction may be used to enforce the inclusion of all uncaught checked exceptions in methods' signals lists; this may be used to assure that any uncaught checked exceptions are intentional.