Version 8 of catch

Updated 2001-12-21 18:52:26

catch - Evaluate script and trap exceptional returns

http://purl.org/tcl/home/man/tcl8.4/TclCmd/catch.htm

 catch script ?varName?  

catch script ?messageVarName? ?optionsVarName? The catch command may be used to prevent errors from aborting command interpretation. Catch calls the Tcl interpreter recursively to execute script, and always returns without raising an error, regardless of any errors that might occur while executing script. If script raises an error, catch will return a non-zero integer value corresponding to one of the exceptional return codes (see tcl.h for the definitions of code values). If the varName argument is given, then the variable it names is set to the error message from interpreting script.

If script does not raise an error, catch will return 0 (TCL_OK) and set the variable to the value returned from script. Note that catch catches all exceptions, including those generated by break and continue and return as well as errors. The only errors that are not caught are syntax errors found when the script is compiled. This is because the catch command only catches errors during runtime. When the catch statement is compiled, the script is compiled as well and any syntax errors will generate a Tcl error.

EXAMPLES

The catch command may be used in an if to branch based on the success of a script.

 if { [catch {open $someFile w} fid] } {
    puts stderr "Could not open $someFile for writing\n$fid"
    exit 1
 }

The catch command will not catch compiled syntax errors. The first time proc foo is called, the body will be compiled and a Tcl error will be generated.

 proc foo {} {    catch {expr {1 +- }}
 }

(from: Tcl Help; bold words added by RS)


Why is it a bad idea to "catch" large chunks of code? Because Tcl stops execution of the code as soon as it encounters an error. This behavior can lead to problems like this: Why is it a bad idea to "catch" large chunks of code? Because Tcl stops execution of the code as soon as it encounters an error. This behavior can lead to problems like this:

    # I've got an open socket whose handle's stored in fid
    catch {
        puts $fid "Here's my last message."
        close $fid
    } err
If the "puts" command generates an error, "catch" detects that and stops execution of the code block. You never get around to closing the channel. It's better practice to put separate "catch" commands around
If the "puts" command generates an error, "catch" detects that and
stops execution of the code block. You never get around to closing the
channel. It's better practice to put separate "catch" commands around
both the "puts" and the "close" commands to detect errors in either
case and handle them appropriately.
This is a different style of programming than in a language like Java. In Java, you can have a variety of exceptions, each represented by a different class, that signal different types of error conditions. Then
This is a different style of programming than in a language like Java.
In Java, you can have a variety of exceptions, each represented by a
different class, that signal different types of error conditions. Then
in a "try" block, you can test for the different types of error
conditions separately and handle them in different ways. (My complaint
about Java is that there seems to be so many different classes, I'm
often at a loss as to which ones I should be testing for.)
In contrast, Tcl generally has only one type of error. In theory, we
could use different return codes to signal different types of error,
but in practice this is hardly ever used.
----

I think it is extreme parochialism to state "it's a bad idea to
code this/that way".  It is perfectly reasonable to catch "large"
chunks:
I think it is extreme parochialism to state "it's a bad idea to code this/that way".  It is perfectly reasonable to catch "large" chunks:
 
 if { [ catch {
    close $fid
} err ] } {
 } err ] } {
    return -code error $err
}
 }
If you catch "large" chunks you can at least have a program that can tolerate some errors that you did not anticipate. It is certainly better to fix problems the first time they appear, but tinkering with the code on a live system is rather poor practice.
If you catch "large" chunks you can at least have a program that
can tolerate some errors that you did not anticipate.
It is certainly better to fix problems the first time they appear,
but tinkering with the code on a "live" system is rather poor
practice.
Most users would rather not have the software come to a screeching
halt on every unanticipated error.
-'''PSE'''
----

[MS]: ''Oops, forgot to mention it here: this bug was closed on 2000-10-25, it is fixed in tcl8.4a4.''

Note that the bytecode compiling of [[catch]] in Tcl 8.x has a bug.
[[catch]] will inappropriately catch errors in the substitution of
its arguments:
 % # should return 'foo'
 % catch [error foo]
 1

Compare with Tcl 7.6:
 % catch [error foo]
 foo

To workaround the bug, defeat the bytecode compiler by generating
[[catch]]:

 % [format catch] [error foo]
 foo

Track Sourceforge bug # 119184 to learn if/when this bug is fixed.
http://sourceforge.net/bugs/?func=detailbug&bug_id=119184&group_id=10894

'''DGP'''
----
Example for caught return, from a posting of [George Petasis] in [the comp.lang.tcl newsgroup]:
 % proc foo {} {
        puts "catch result is :[catch { return}]"
        puts "after return"
 } 
 % foo
 catch result is :2
 after return 

For a more complex worked example of catching [break], [continue], [error] and [return], this Wiki has a pure Tcl implementation of a Java-style try ... finally ... construct. -- KBK 24 Dec 2000


When you [catch] the result of an [exec] command, $::errorCode contains a wealth of information about what happened. See the exec page for how to take it apart.


throw: The logical opposite to catching is throwing. Tcl has no throw command, but still you can call it. And guess what, it ends up in the hands of catch.. see Fraction math, proc quotient_rep. Now is this the Zen of Tcl, or what?


See also Tcl performance: catch vs. info for the slowness of catch.


A common use for catch is when invoking external commands via exec . Since any non-zero return code would otherwise result in a raised error, one typically wraps the invocation with catch and then checks for the appropriate things. Since grep is just one example of a Unix command which uses a non-zero return code to mean something other than error, one needs to be aware of cases like this when writing the exec.

[does someone have an idiom for execing a command, capturing the stdout, stderr, return code, etc. testing the return code and producing useful output based on stderr when appropriate, etc.?


Tcl syntax help - Arts and crafts of Tcl-Tk programming Category Command