NAME

try - Exception handling

SYNOPSIS

try script ?catch msg catchblock? ?finally finallyscript? ?varName?
try script ?catch {type msg} catchblock? ?finally finallyscript? ?varName?

DESCRIPTION

The try command is used to catch exceptions or errors generated by throw or error. Its use is similar to catch, but with several differences: it encapsulates exception catching and handling, whereas catch only does (as its name says) error catching.

Usually, a test is made on catch's return value to see if an error has been caught. In this case, error handling is done depending on catch's return code and the errorInfo and errorCode global variables value. The purpose of try is to gather error catching and handling in a single statement. To do so, it uses a C++/Java-like exception-handling syntax.

Try first evaluates script. If no error occurs, it then evaluates (if present) finallyscript following the finally keyword (borrowed from the Java language). However, if an error occurs, the evaluation of the script is interrupted and try tries to match the exception type to one of those defined in the catchblock following the catch keyword and evaluates the body of the matching type. If none is found (or if no catch block is present) then it evaluates finallyscript and propagates the exception to lower levels. The exception is propagated until it reaches a try or catch statement, or the global level. It is important to know that finallyscript is always evaluated, even if the exception is unhandled and propagated. This script is generally used for clean-up purpose. The finally keyword is a major improvement to C++ exceptions introduced by Java.

The catch block is very similar to the pattern-body list used with switch. It is a list (which can be empty) with a {type body ?type body ...?} structure. When an exception is caught, try compares each type with the exception type (see throw and exception for explanation on exception types and how they are matched). If the last type is default then it matches any type. When the first matching type is found, the corresponding body is evaluated. Msg is the name of a variable that will contain the exception message that can be used inside catch block bodies, and with the second form, type will also contain the exception type.

Like in switch, comments are not allowed inside a catch block, since a catch block is not a valid Tcl script. However, bodies must be valid Tcl scipts. Thus, unlike switch, the body cannot be specified as "-" to specify that the following body must be used.

Try handles all the exceptions thrown by the throw command. It also handles regular Tcl errors generated by return and error commands and by Tcl core commands. In these cases, the exception type is Error. Future versions of throw are likely to use more precise exception types (for example, FileException in case of file I/O error). However, unlike catch, control flow commands such as return, break or continue are not caught, so you can use try statements inside a loop, or exit a procedure from within a try statement.

Unlike C++ or Java, exception types are not objects nor structures. They are just strings. So there is no inheritance relationship between exception types. This is likely to change in future versions, since exception subtyping is very handy.

If present, varName is the name of a variable that will contain the return value of the last evaluated command in any of the scripts.

If no error occurs inside a catch body or the finally script, then try, like catch, returns a decimal string giving the code returned by the script. In this case, try behaves like catch, except that it does not catch return/break/continue exceptions. However, errors that occur inside a catch body or a finally script are not handled and then raise an error.

EXAMPLES

will print: What happened:

Try first evaluates the main script. It first prints "begin". The "throw ..." command throws an exception of type MyException. The main script evaluation is then interrupted, and since there is a catch keyword, try looks for the first matching exception type, which is present, and evaluates its body, thus prints the error message. The 1 is the value returned by try, indicating that an error occurred.

will print: This is the same example as above, except that there is a finally keyword. The finally script is then evaluated. will print: There is no exception type matching UnhandledException here, so the exception is propagated, but after the finally script being evaluated. The last line is the error message received at global level. will print: Here the default keyword in the catch block matches the UnhandledException. will print: The Error exception type matches regular Tcl errors.

Examples of try inside loops:

will print numbers from 0 to 9 not including 5. Thus the continue is correctly propagated. The following: will print numbers from 0 to 4. The following: will print numbers from 0 to 5. The difference is that the puts is inside a finally block, and thus gets executed even after the loop has been broken.

Example of try within a proc:

will print "begin", numbers from 0 to 4 then "finally", but not "end".

Of course, try statements can be nested. You can put them within any Tcl control structure, within a catch script, within a try main script, catch body or finally script, and in anything that can be evaluated by Tcl. Put them everywhere!

KNOWN BUGS/LIMITATIONS

When using return from within a try, catch or finally block with a non-error code, -errorinfo and -errorcode options have no effect. But since catch behaves the same, this should be called a feature, or compatibility ;-)

SEE ALSO

catch(n), error(n), return(n), throw, exception

KEYWORDS

error, exception