<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE TIP SYSTEM "http://www.tcl.tk/cgi-bin/tct/tip/tipxml.dtd">
<!-- Converted at Tue May 21 09:46:22 GMT 2013 -->
<!-- TIP AutoGenerator - written by Donal K. Fellows -->

<TIP number='329'>
<header><title>Try/Catch/Finally syntax</title><author address="mailto:twylite@crypt.co.za">Trevor Davel</author><status type='project' state='final' tclversion="8.6" vote='after'>$Revision: 1.9 $</status><history></history><created day='22' month='sep' year='2008' /><discussions url='http://wiki.tcl.tk/21608'/><obsoletes tip='89'/></header>
<abstract>This TIP proposes the addition of new core commands to improve the exception handling mechanism. It supercedes <tipref type="text" tip="89"/> by providing support for the error options dictionary introduced in Tcl 8.5 by <tipref type="text" tip="90"/>.</abstract>
<body><section title="Rationale">
<para>See <tipref type="text" tip="89"/> for general rationale for enhancing exception handling.</para>
<para>The <emph style="bold">try</emph> syntax presented here is not intended to replace <emph style="bold">catch</emph>, but to simplify the expression of existing exception/error handling techniques, leading to greater code clarity and less error-prone workarounds for <emph style="bold">finally</emph> blocks. There is no deficiency in the functionality of Tcl&apos;s exception handling mechanisms - what is lacking is a more readable syntax and a standard for behaviour across packages for the common case of catching a subset errors or exceptions that are thrown from within a particular block of code.</para>
<para>In Tcl 8.4 exceptions could be caught using <emph style="bold">catch</emph>, and exception information was available via the <emph style="bold">catch</emph> return value and resultvar. If the return value was TCL_ERROR (1) then the globals <emph style="bold">::errorCode</emph> and <emph style="bold">::errorInfo</emph> would be set according to the exception raised. <tipref type="text" tip="89"/> was written to work with this model, such that a catch handler (in a <emph style="bold">try...catch</emph>) would be able to capture the resultvar, errorCode and errorInfo.</para>
<para>Tcl 8.5 implements <tipref type="text" tip="90"/> which extends <emph style="bold">catch</emph> to allow an additional dictionary of options (error information) to be captured. These options supercede the <emph style="bold">::errorInfo</emph> and <emph style="bold">::errorCode</emph> globals (though those are still supported for backward compatibility). It is therefore logical to extend/correct the syntax of <tipref type="text" tip="89"/> to support the options dictionary in preference to the older mechanism for capturing exception information.</para>
<para>Benefits of adding this functionality to the core:</para>
<itemize><item.i><para>Bring to Tcl a construct commonly understood and widely used in other languages.</para></item.i><item.i><para>A standard for identifying categories/classes of errors, which will improve interoperability between packages.</para></item.i><item.i><para>A byte-coded implementation would be significantly faster than the Tcl implementation that is presented.</para></item.i></itemize>
</section>
<section title="Specification">
<quote><emph style="bold">try</emph> <emph style="italic">body</emph> ?<emph style="italic">handler</emph> ...? ?<emph style="bold">finally</emph> <emph style="italic">body</emph>?</quote>
<quote><emph style="bold">throw</emph> <emph style="italic">type message</emph></quote>
<para>The <emph style="bold">try</emph> body is evaluated in the caller&apos;s scope. The handlers are searched in order of declaration until a matching one is found, and the associated body is executed. If no matching handler is found then <emph style="bold">try</emph> returns the result of the <emph style="bold">try</emph> body (exceptions will propagate up the stack as usual); otherwise <emph style="bold">try</emph> returns the result of the handler body (exceptions will propagate up the stack as usual).</para>
<para>Only one handler body (that of the first matching handler) will be executed. If the handler body is the literal string &quot;<emph style="bold">-</emph>&quot; then the body for the subsequent handler will be used instead. It is an error for the last handler&apos;s body to be a literal &quot;<emph style="bold">-</emph>&quot;.</para>
<para>The <emph style="bold">finally</emph> body (if present) will be executed last, and is always executed whatever the results of the try and handler bodies (excepting resource exhaustion or cancellation). If the <emph style="bold">finally</emph> body returns an exceptional code then this will become the result of <emph style="bold">try</emph>, otherwise the result of the <emph style="bold">finally</emph> body is ignored.</para>
<para>Since the <emph style="bold">trap</emph> handlers in the <emph style="bold">try</emph> control structure are filtered based on the exception&apos;s <emph style="bold">-errorcode</emph>, it makes sense to have a command that will encourage the use of error codes when throwing an exception. <emph style="bold">throw</emph> is merely a reordering of the arguments of the <emph style="bold">error</emph> command. <emph style="italic">type</emph> is treated as a list by <emph style="bold">trap</emph> (see below), which maintains compatibility with the description of ::errorCode given in <emph style="bold">tclvars</emph>.</para>
<subsection title="Handlers">
<para>Each handler is identified by a keyword. The fields following the keyword indicate what exceptions or errors are matched by the handler, the variables into which the result of the <emph style="bold">try</emph> body will be assigned (in the caller&apos;s scope), and the body of the handler.</para>
<quote><emph style="bold">on</emph> <emph style="italic">code {?resultVar ?optionsVar?} body</emph></quote>
<para>The <emph style="bold">on</emph> handler allows exact matching against the exceptional return code (the integer value that would be returned by <emph style="bold">catch</emph>). The <emph style="italic">code</emph> may be given as an integer or one of the magic keywords <emph style="bold">ok</emph> (0), <emph style="bold">error</emph> (1), <emph style="bold">return</emph> (2), <emph style="bold">break</emph> (3), <emph style="bold">continue</emph> (4).</para>
<quote><emph style="bold">trap</emph> <emph style="italic">pattern {?resultVar ?optionsVar?} body</emph></quote>
<para>The <emph style="bold">trap</emph> handler allows list prefix matching against the <emph style="bold">-errorcode</emph> from the options when the exceptional return code is TCL_ERROR (1). Given a <emph style="italic">pattern</emph> and an <emph style="italic">errorcode</emph>, a list prefix match is successful if for every element in <emph style="italic">pattern</emph> there is a corresponding and identical element in <emph style="italic">errorcode</emph>. Trailing elements in <emph style="italic">errorcode</emph> are ignored.</para>
<para>Notes &amp; clarifications:</para>
<itemize><item.i><para>Handlers are searched in order of declaration (left-to-right). One consequence of this search order is that an <emph style="bold">on error</emph> handler will supercede all subsequent <emph style="bold">trap</emph> handlers.</para></item.i><item.i><para>Any unhandled exception propagates.</para></item.i><item.i><para>The result of the last executed body (other than the <emph style="bold">finally</emph> body) is the result of the <emph style="bold">try</emph>. Exceptions in any <emph style="italic">handler</emph> body or in the <emph style="bold">finally</emph> replace the existing exception and propagate.</para></item.i><item.i><para>If any exception is replaced (by an exception in a handler body or in the <emph style="bold">finally</emph> body) then the new exception shall introduce into its options dictionary the field <emph style="bold">-during</emph> that contains the options dict of the exception that was replaced.</para></item.i><item.i><para>If any errorcode happens to be not a list, a <emph style="bold">trap</emph> handler will be unable to process it. However, this should only happen in cases where there is a bug or other problem elsewhere, since <emph style="bold">return</emph> is documented to require the errorcode to be a list.</para></item.i></itemize>
</subsection>
</section>
<section title="Examples">
<para>Simple example of <emph style="bold">try</emph>/<emph style="italic">handler</emph>/<emph style="bold">finally</emph> logic in Tcl using currently available syntax:</para>
<verbatim><vline encoding='base64'>IHByb2MgcmVhZF9oZXhfZmlsZSB7Zm5hbWV9IHs=</vline><vline encoding='base64'>ICAgIHNldCBmIFtvcGVuICRmbmFtZSAiciJd</vline><vline encoding='base64'>ICAgIHNldCBkYXRhIHt9</vline><vline encoding='base64'>ICAgIHNldCBjb2RlIFtjYXRjaCB7</vline><vline encoding='base64'>ICAgICAgIHdoaWxlIHsgW2dldHMgJGYgbGluZV0gPj0gMCB9IHs=</vline><vline encoding='base64'>ICAgICAgICAgIGFwcGVuZCBkYXRhIFtiaW5hcnkgZm9ybWF0IEgqICRsaW5lXQ==</vline><vline encoding='base64'>ICAgICAgIH0=</vline><vline encoding='base64'>ICAgIH0gZW0gb3B0c10=</vline><vline encoding='base64'>ICAgIGlmIHsgJGNvZGUgIT0gMCB9IHs=</vline><vline encoding='base64'>ICAgICAgIGRpY3Qgc2V0IG9wdHMgLWNvZGUgMQ==</vline><vline encoding='base64'>ICAgICAgIHNldCBlbSAiQ291bGQgbm90IHByb2Nlc3MgZmlsZSAnJGZuYW1lJzogJGVtIg==</vline><vline encoding='base64'>ICAgIH0=</vline><vline encoding='base64'>ICAgIGNsb3NlICRm</vline><vline encoding='base64'>ICAgIHJldHVybiAtb3B0aW9ucyAkb3B0cyAkZW0=</vline><vline encoding='base64'>IH0=</vline></verbatim>
<para>And the same example rewritten to use [<emph style="bold">try</emph>]:</para>
<verbatim><vline encoding='base64'>IHByb2MgcmVhZF9oZXhfZmlsZSB7Zm5hbWV9IHs=</vline><vline encoding='base64'>ICAgIHNldCBmIFtvcGVuICRmbmFtZSAiciJd</vline><vline encoding='base64'>ICAgIHNldCBkYXRhIHt9</vline><vline encoding='base64'>ICAgIHRyeSAgew==</vline><vline encoding='base64'>ICAgICAgIHdoaWxlIHsgW2dldHMgJGYgbGluZV0gPj0gMCB9IHs=</vline><vline encoding='base64'>ICAgICAgICAgYXBwZW5kIGRhdGEgW2JpbmFyeSBmb3JtYXQgSCogJGxpbmVd</vline><vline encoding='base64'>ICAgICAgIH0=</vline><vline encoding='base64'>ICAgIH0gdHJhcCB7UE9TSVh9IHt9IHs=</vline><vline encoding='base64'>ICAgICAgIHB1dHMgIlBPU0lYLXR5cGUgZXJyb3Ii</vline><vline encoding='base64'>ICAgIH0gb24gZXJyb3Ige2VtfSB7</vline><vline encoding='base64'>ICAgICAgIGVycm9yICJDb3VsZCBub3QgcHJvY2VzcyBmaWxlICckZm5hbWUnOiAkZW0i</vline><vline encoding='base64'>ICAgIH0gZmluYWxseSB7</vline><vline encoding='base64'>ICAgICAgIGNsb3NlICRm</vline><vline encoding='base64'>ICAgIH0=</vline><vline encoding='base64'>IH0=</vline></verbatim>
<para>This illustrates how the intent of the code is more clearly expressed by [<emph style="bold">try</emph>].</para>
</section>
<section title="References">
<itemize><item.i><para>Tcl 8.4 catch [<url ref="http://www.tcl.tk/man/tcl8.4/TclCmd/catch.htm"/>]</para></item.i><item.i><para>Tcl 8.5 catch [<url ref="http://www.tcl.tk/man/tcl8.5/TclCmd/catch.htm"/>]</para></item.i></itemize>
</section>
<section title="Rejected Alternatives">
<para>Various alternatives are discussed on the wiki [<url ref="http://wiki.tcl.tk/21608"/>] along with reasons for their rejection.</para>
</section>
<section title="Future Extensions">
<para>No specific future exceptions are planned, but <emph style="bold">try</emph> could be extended by adding new handler keywords and/or introducing new varnames to the variables list that is associated with each handler.</para>
<para>It is recommended that new handlers maintain the established convention:</para>
<quote><emph style="bold">keyword</emph> <emph style="italic">criteria {?resultVar ?optionsVar?} body</emph></quote>
</section>
<section title="Reference Implementation">
<para>A reference implementation can be found at [<url ref="http://www.crypt.co.za/pub/try-1.tcl"/>]</para>
</section>
<section title="Thanks">
<para>Thanks in particular to DKF, NEM and JE for their feedback and suggestions on this TIP.</para>
</section>
<section title="Copyright">
<para>This document has been placed in the public domain.</para>
</section>
</body></TIP>
