| 1 | |
|---|
| 2 | <html><head> |
|---|
| 3 | <title>trycatch</title> |
|---|
| 4 | </head> |
|---|
| 5 | |
|---|
| 6 | <BODY> |
|---|
| 7 | |
|---|
| 8 | <h1>trycatch</h1> |
|---|
| 9 | |
|---|
| 10 | <h2><a name="synopsis">SYNOPSIS</a></h2> |
|---|
| 11 | |
|---|
| 12 | <pre> |
|---|
| 13 | package require trycatch 2.0 |
|---|
| 14 | namespace import trycatch::* |
|---|
| 15 | |
|---|
| 16 | try {...} |
|---|
| 17 | try {...} catch ?-msg msgVar? ?-code codeVar? ?-info infoVar? {...} |
|---|
| 18 | try {...} finally {...} |
|---|
| 19 | |
|---|
| 20 | throw code message |
|---|
| 21 | |
|---|
| 22 | onerr ?-code errorCode? pattern {...} pattern {...} ... |
|---|
| 23 | </pre><p> |
|---|
| 24 | |
|---|
| 25 | <h2><a name="description">DESCRIPTION</a></h2> |
|---|
| 26 | |
|---|
| 27 | Most modern languages, from C++ to Java to Python, have some kind of |
|---|
| 28 | exception-handling control structure, usually called something like |
|---|
| 29 | "try". In Tcl, the equivalent mechanism is the built-in "catch" |
|---|
| 30 | command, which has two faults: it has an inconvenient syntax, and it |
|---|
| 31 | functions at very low level. It's really more of a tool for writing |
|---|
| 32 | control structures.<p> |
|---|
| 33 | |
|---|
| 34 | The trycatch package defines a general purpose exception-handling |
|---|
| 35 | control structure on top of the standard "catch" command. The |
|---|
| 36 | following commands are defined:<p> |
|---|
| 37 | |
|---|
| 38 | <dl> |
|---|
| 39 | <dt> <code>try {<i>tryscript</i>}</code> |
|---|
| 40 | <dd> The <i>tryscript</i> is executed; if an error is raised during |
|---|
| 41 | execution, it is caught and ignored. For example,<p> |
|---|
| 42 | <pre> |
|---|
| 43 | proc div {a b} { |
|---|
| 44 | set quotient "NaN" |
|---|
| 45 | try { |
|---|
| 46 | set quotient [expr {$a/$b}] |
|---|
| 47 | } |
|---|
| 48 | return $quotient |
|---|
| 49 | } |
|---|
| 50 | </pre> |
|---|
| 51 | |
|---|
| 52 | This function will return the quotient of the two inputs, or |
|---|
| 53 | "NaN" (Not a Number) if for any reason the computation |
|---|
| 54 | failed.<p> |
|---|
| 55 | |
|---|
| 56 | Note that if the <i>tryscript</i> contains "return", "break", |
|---|
| 57 | or "continue" commands, they will function as one would |
|---|
| 58 | expect. For example, the above function could be rewritten as |
|---|
| 59 | follows:<p> |
|---|
| 60 | |
|---|
| 61 | <pre> |
|---|
| 62 | proc div {a b} { |
|---|
| 63 | try { |
|---|
| 64 | return [expr {$a/$b}] |
|---|
| 65 | } |
|---|
| 66 | return "NaN" |
|---|
| 67 | } |
|---|
| 68 | </pre> |
|---|
| 69 | |
|---|
| 70 | If there's no error computing the quotient, the computed value |
|---|
| 71 | will be returned; but if there is, control will continue with |
|---|
| 72 | the code following the "try", and "NaN" will be returned.<p> |
|---|
| 73 | |
|---|
| 74 | <dt> <code>try {<i>tryscript</i>} catch ?options? {<i>catchscript</i>}</code> |
|---|
| 75 | <dd> Sometimes it's not enough to just ignore an error; you need to |
|---|
| 76 | take special action. In this form, the <i>tryscript</i> is |
|---|
| 77 | executed; if it executes without error, control continues with |
|---|
| 78 | the statement after the "catch" clause. Otherwise, the "catch" |
|---|
| 79 | clause is executed as follows:<p> |
|---|
| 80 | |
|---|
| 81 | <ul> |
|---|
| 82 | <li> If the "-msg" option is given, its value is a variable |
|---|
| 83 | name; the variable is set to the raised error message.<p> |
|---|
| 84 | |
|---|
| 85 | <li> If the "-code" option is given, its value is a variable |
|---|
| 86 | name; the variable is set to that of the global |
|---|
| 87 | "errorCode" variable.<p> |
|---|
| 88 | |
|---|
| 89 | <li> If the "-info" option is given, its value is a variable |
|---|
| 90 | name; the variable is set to that of the global |
|---|
| 91 | "errorInfo" variable.<p> |
|---|
| 92 | |
|---|
| 93 | <li> The <i>catchscript</i> is executed. If an error is |
|---|
| 94 | raised in the <i>catchscript</i>, it propagates |
|---|
| 95 | normally; otherwise execution will continue with the |
|---|
| 96 | statement after the "try/catch" structure.<p> |
|---|
| 97 | |
|---|
| 98 | <li> Any "return", "break", or "continue" commands in the |
|---|
| 99 | <i>catchscript</i> are handled as you'd expect.<p> |
|---|
| 100 | </ul><p> |
|---|
| 101 | |
|---|
| 102 | For example, the division example could be written as follows:<p> |
|---|
| 103 | |
|---|
| 104 | <pre> |
|---|
| 105 | proc div {a b} { |
|---|
| 106 | try { |
|---|
| 107 | return [expr {$a/$b}] |
|---|
| 108 | } catch -msg msg { |
|---|
| 109 | puts "Warning: arithmetic error in 'div $a $b': $msg" |
|---|
| 110 | return "NaN" |
|---|
| 111 | } |
|---|
| 112 | } |
|---|
| 113 | </pre> |
|---|
| 114 | |
|---|
| 115 | <dt> <code>try {<i>tryscript</i>} finally {<i>finallyscript</i>}</code> |
|---|
| 116 | <dd> This form is rather different than the first two. It executes |
|---|
| 117 | the <i>tryscript</i> as they do. But instead of |
|---|
| 118 | catching any errors in the <i>tryscript</i>, it allows them to |
|---|
| 119 | propagate up the call-chain. Whether there is an error or not, |
|---|
| 120 | however, the <i>finallyscript</i> is always executed.<p> |
|---|
| 121 | |
|---|
| 122 | The "try/finally" form is used when a particular action |
|---|
| 123 | must be taken, no matter what else happens. For example, suppose a |
|---|
| 124 | program opens a file and begins to write to it. If an error occurs, |
|---|
| 125 | writing will end; but the file must be closed whether the file is |
|---|
| 126 | written successfully or not. For example:<p> |
|---|
| 127 | |
|---|
| 128 | <pre> |
|---|
| 129 | set f [open "foo.dat" w] |
|---|
| 130 | |
|---|
| 131 | try { |
|---|
| 132 | # Write various things to the file |
|---|
| 133 | } finally { |
|---|
| 134 | close $f |
|---|
| 135 | } |
|---|
| 136 | </pre> |
|---|
| 137 | |
|---|
| 138 | If an error occurs while writing, the finally clause will be executed, |
|---|
| 139 | and then the error will be propagated normally.<p> |
|---|
| 140 | |
|---|
| 141 | Similarly, if the <i>tryscript</i> contains "break", |
|---|
| 142 | "continue", or "return" commands they will be handled as one |
|---|
| 143 | would expect--but the <i>finallyscript</i> will be executed first.<p> |
|---|
| 144 | |
|---|
| 145 | If the <i>finallyscript</i> contains "break", "continue", or |
|---|
| 146 | "return" commands, an error will be raised. |
|---|
| 147 | Errors in the <i>finallyscript</i> will be propagated normally.<p> |
|---|
| 148 | |
|---|
| 149 | <dt> throw <i>code</i> <i>message</i> |
|---|
| 150 | <dd> The usual way to raise an error in Tcl is to use the "error" |
|---|
| 151 | command. This command signals that an error has occurred, and |
|---|
| 152 | specifies a human-readable error message; it may also specify |
|---|
| 153 | "errorInfo", used to build a traceback, and an "errorCode", a |
|---|
| 154 | machine-readable version of the error message. There are a |
|---|
| 155 | number of standard error codes used by Tcl itself; see the |
|---|
| 156 | description of the "errorCode" variable in the Tcl |
|---|
| 157 | documentation for more information. (Look under "tclvars".)<p> |
|---|
| 158 | |
|---|
| 159 | Although it can be very useful, few Tcl packages bother to |
|---|
| 160 | include error codes when they raise errors. The "throw" |
|---|
| 161 | command is intended to encourage this worthy practice by |
|---|
| 162 | putting the <i>code</i> first and the <i>message</i> second. |
|---|
| 163 | The <i>code</i> should be a valid Tcl list of one or more |
|---|
| 164 | elements. A typical pattern might be for the first token to be |
|---|
| 165 | the package name, and the second to be a code identifying the |
|---|
| 166 | specific error. Thus, for example, if the "try" command |
|---|
| 167 | detects a syntax error it might throw the following error:<p> |
|---|
| 168 | |
|---|
| 169 | <pre> |
|---|
| 170 | throw {trycatch syntax} "syntax: try {...} ...." |
|---|
| 171 | </pre> |
|---|
| 172 | |
|---|
| 173 | <dt> onerr ?-code <i>errorCode</i>? <i>pattern script</i> ... |
|---|
| 174 | <dd> The onerr command is typically used within the catch clause |
|---|
| 175 | of a try/catch statement to match and handle particular |
|---|
| 176 | errors. Suppose, for example, it's desired to divide two |
|---|
| 177 | numbers; we might wish to handle badly formed input separately |
|---|
| 178 | from divide-by-zero errors:<p> |
|---|
| 179 | |
|---|
| 180 | <pre> |
|---|
| 181 | proc div {a b} { |
|---|
| 182 | try { |
|---|
| 183 | return [expr {$a/$b}] |
|---|
| 184 | } catch -msg msg { |
|---|
| 185 | onerr {ARITH DIVZERO} { |
|---|
| 186 | return "NaN" |
|---|
| 187 | } * { |
|---|
| 188 | error "div failed: $msg" |
|---|
| 189 | } |
|---|
| 190 | } |
|---|
| 191 | } |
|---|
| 192 | </pre> |
|---|
| 193 | |
|---|
| 194 | The onerr command works by trying to match <i>patterns</i> against the |
|---|
| 195 | specified <i>errorCode</i>; if a pattern matches, the subsequent |
|---|
| 196 | <i>script</i> is executed. The error code to match is the value of |
|---|
| 197 | the -code option, if any, or the value of the global variable |
|---|
| 198 | errorCode.<p> |
|---|
| 199 | |
|---|
| 200 | The error code is a Tcl list; each error pattern should be a |
|---|
| 201 | Tcl list of glob-patterns (see the "string match" command for |
|---|
| 202 | more on glob-patterns). The onerr command tries to match each |
|---|
| 203 | glob-pattern with the corresponding token in the error code; if |
|---|
| 204 | there is a mismatch, or if there are more glob-patterns than |
|---|
| 205 | error code tokens, then onerr goes on to the next pattern.<p> |
|---|
| 206 | |
|---|
| 207 | It is usual to provide a default error handler, using the |
|---|
| 208 | single glob pattern "*". This matches the first token of any |
|---|
| 209 | error code, and therefore will match any error code which |
|---|
| 210 | hasn't yet been matched.<p> |
|---|
| 211 | </dl> |
|---|
| 212 | <p> |
|---|
| 213 | |
|---|
| 214 | <h2><a name="history">HISTORY</a></h2> |
|---|
| 215 | |
|---|
| 216 | <code>trycatch</code> was written by William H. Duquette.<p> |
|---|
| 217 | |
|---|
| 218 | Version 2.0 added the "try" and "try/finally" forms of the command, |
|---|
| 219 | changed the syntax of the "catch" clause, and added the "throw" and |
|---|
| 220 | "onerr" commands. |
|---|
| 221 | |
|---|
| 222 | |
|---|
| 223 | <p><hr><p> |
|---|
| 224 | Copyright © 2001, by William H. Duquette. All rights reserved.<p> |
|---|
| 225 | |
|---|
| 226 | |
|---|
| 227 | |
|---|
| 228 | </body> |
|---|
| 229 | </html> |
|---|