Exception Handling - the try Statement
Calling Sequence
Description
Exception Handling Statements within Expression
Examples
Exception Handling Statement
try <tryStatSeq>
| catch <catchStrings> : <catchStatSeq> |
| finally <finalStatSeq> |
end try
Note: | | indicates an optional phrase.
The try statement provides a mechanism for executing statements in a controlled environment, where errors will not just cause the execution to halt with no warning.
When execution enters a try statement, tryStatSeq is executed.
If no exception occurs during the execution of tryStatSeq, execution continues with finalStatSeq (if a finally clause was specified). After that, execution continues with the statement after the end try keywords.
The construct catch <catchStrings> : <catchStatSeq> can be repeated any number of times.
If an exception does occur during the execution of tryStatSeq, execution of tryStatSeq terminates immediately. The exception object that corresponds to the exception is compared against each catchString in turn until a match is found.
If a matching catch clause is found, the catchStatSeq of that catch clause is executed, and the exception is considered to have been caught. If no matching catch clause is found, the exception is considered not-caught, and is re-raised outside the try construct. Note that if a try statement has no catch clauses, then no exceptions are caught.
A catchStatSeq can contain an error statement with no arguments, which re-raises the exception.
When an exception is re-raised, a new exception object is created that records the current procedure name, and the msgString and msgParams from the original exception.
Under normal circumstances, the finalStatSeq of the finally clause (if there is one) is always executed before the control leaves the try statement, regardless of whether the tryStatSeq executes a return, break, or next statement, an exception occurs, an exception is caught, or another exception occurs in the catch clause that caught the exception. This is true even if a catchStatSeq re-raises the exception, raises a new one, or executes a return, break, or next statement.
If an exception is raised in a catch clause and this exception is caught by the debugger and the user exits the debugger, the user's command to stop execution overrides everything, and the finalStatSeq is not executed.
Some exceptions are untrappable. This means that a catch clause will never match such an exception, even if the catchString is missing. The finalStatSeq is also not executed if an untrappable exceptions occurs. The following exceptions are untrappable:
Computation timed out (this can only be caught by timelimit, which raises a "time expired" exception, which can be caught).
Computation interrupted (user pressed Ctrl+C, Break, or equivalent).
Internal system error (which indicates a bug in Maple itself).
ASSERT or return type or local variable type assertion failure (assertion failures are not trappable because they indicate a coding error, not an algorithmic failure).
Stack overflow (when that happens, generally stack space is insufficient for doing anything like running cleanup code). This includes the "too many levels of recursion" exception at the Maple language level.
An error that occurs during simplification of the try statement itself will not be caught, and the finally clause, if any, will not be executed, because the try statement is not yet being executed at that point.
If an exception occurs during the execution of a catchStatSeq or the finalStatSeq, it is treated in the same way as though it occurred outside the try...end try statement entirely.
If the tryStatSeq or a catchStatSeq executes a return statement, this value is returned from the enclosing procedure. If a finally clause is present, it is executed before returning, but does not affect the value returned unless the finalStatSeq itself executes a return statement (which will change the returned value), or if in a loop, a break or next statement (which will abort the return). Doing this is not recommended, as it makes control flow difficult to follow.
When looking for a matching catch clause, note the following:
Neither the exception object nor the catchStrings are evaluated. (The exception object will already have been evaluated by the error statement that produced it.)
The catchStrings are considered to be prefixes of the exception object's msgString. If a catchString has n characters, only the first n characters of the msgString have to match the catchString. This allows one to define classes of exceptions.
A missing catchString will match any exception.
The "result" of a try statement (the value that % would return if evaluated immediately after execution of the try statement) is the result of the last statement executed within the try statement.
A given catchString (or a catch clause without one) can appear only once in a try...end construct.
The end try that terminates a selection statement can be shortened to just end if desired.
If a try statement contains no catch clauses and also no finally clause, a warning is produced during simplification, and the try statement is replaced by the tryStatSeq.
A limited functional form of exception handling is available via the traperror function. Unlike an exception handling statement, this catches any exception that occurs (i.e. like an empty catch: clause would), and when one does occur, returns the text of the error message as the result. See the traperror help page for more information.
An actual exception handling statement can be used as an expression or subexpression. Unlike the aforementioned traperror function, and embedded exception handling statement can be selective about which exceptions it catches, and what to return as a result in each case. Since it can have a finally clause, it can also perform any necessary clean-up.
The value of such an embedded exception handling statement is the value of the last expression computed within the last branch that was executed:
If there was a non-empty finally clause, the result is that of the last expression computed in the finalStatSeq.
If no exception occurred, the result is that of the last expression computed in the tryCatchSeq.
If an exception did occur and was caught, the result is that of the last expression computed in the relevant catchStatSeq.
If there was an exception and it was not caught, the evaluation of the entire expression is aborted just as it would be if no exception handling statement were involved.
Note: Exception handling statements embedded within expressions are currently not supported in 2-D input in the Standard interface.
Try one method, and if it fails by executing error "FAIL", try a second method. If the first method throws an "invalid arguments" or "division by zero" error, give a more meaningful error message. Any other error from the first method will not be trapped.
try result := MethodA(f,x) catch "FAIL": result := MethodB(f,x) catch "invalid arguments", "division by zero": error "something went wrong calling MethodA" end try;
Read lines from a file, making sure the file is closed even if something goes wrong while processing the lines:
f := fopen("myfile",READ,TEXT):
try line := readline(f); while line <> 0 do ProcessContentsOfLine(line); line := readline(f) end do finally fclose(f) end try;
Write lines to a file. If something goes wrong, print a message and then re-raise the exception. Close the file no matter what happened.
f := fopen("myfile",WRITE,TEXT):
try for i to 100 do fprintf(f,"Result %d is %q\n",i,ComputeSomething(i)) end do catch: fprintf(f,"Something went wrong: %q\n",lastexception); error finally fclose(f) end try;
Compute the value of f(x), returning infinity if a division by zero occurs. Any other exception should not be caught:
f := proc( x::numeric, $ ) 1/x end proc:
for x in [ 2, 0, "Not-a-number" ] do print('f'(x) = try f(x) catch "numeric exception: div": infinity end try) end do;
f⁡2=12
f⁡0=∞
Error, invalid input: f expects its 1st argument, x, to be of type numeric, but received Not-a-number
See Also
error
return
Download Help Document