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

<TIP number='90'>
<header><title>Enable [return -code] in Control Structure Procs</title><author address="mailto:dgp@users.sf.net">Don Porter</author><author address="mailto:fellowsd@cs.man.ac.uk">Donal K. Fellows</author><status type='project' state='final' tclversion="8.5" vote='after'>$Revision: 1.39 $</status><history></history><created day='15' month='mar' year='2002' /></header>
<abstract>This TIP analyzes existing limitations on the coding of control structure commands as <emph style="italic">proc</emph>s, and presents expanded forms of <emph style="italic">catch</emph> and <emph style="italic">return</emph> to remove those limitations.</abstract>
<body><section title="Background">
<para>It is a distinguishing feature of Tcl that everything is a command, including control structure functionality that in many other languages are part of the language itself, such as <emph style="italic">if</emph>, <emph style="italic">for</emph>, and <emph style="italic">switch</emph>. The command interface of Tcl, including both a return code and a result, allows extensions to create their own control structure commands.</para>
<para>Control structure commands have the feature that one or more of their arguments is a script, often called a <emph style="italic">body</emph>, meant to be evaluated in the caller&apos;s context. The control structure command exists to control whether, when, in what context, or how many times that script is evaluated. When the body is evaluated, however, it is intended to behave as if it were interpreted directly in the place of the control structure command.</para>
<para>The built-in commands of Tcl provide the ability for scripts themselves to define new commands. Notably, the <emph style="italic">proc</emph> command makes this possible. In addition, other commands such as <emph style="italic">catch</emph>, <emph style="italic">return</emph>, <emph style="italic">uplevel</emph>, and <emph style="italic">upvar</emph> offer enough control and access to the caller&apos;s context that it is possible to create new control structure commands for Tcl, entirely at the script level.</para>
<para>Almost.</para>
<para>There is one limitation that separates control structure commands created by <emph style="italic">proc</emph> from those created in C by a direct call to <emph style="italic">Tcl_Create(Obj)Command</emph>. It is most easily seen in the following example that compares the built-in command <emph style="italic">while</emph> to the command <emph style="italic">control::do</emph> created by <emph style="italic">proc</emph> in the control package of tcllib.</para>
<verbatim><vline encoding='base64'>ICAlIHBhY2thZ2UgcmVxdWlyZSBjb250cm9s</vline><vline encoding='base64'>ICAlIHByb2MgYSB7fSB7d2hpbGUgMSB7cmV0dXJuIC1jb2RlIGVycm9yfX0=</vline><vline encoding='base64'>ICAlIHByb2MgYiB7fSB7Y29udHJvbDo6ZG8ge3JldHVybiAtY29kZSBlcnJvcn0gd2hpbGUgMX0=</vline><vline encoding='base64'>ICAlIGNhdGNoIGE=</vline><vline encoding='base64'>ICAx</vline><vline encoding='base64'>ICAlIGNhdGNoIGI=</vline><vline encoding='base64'>ICAw</vline></verbatim>
<para>The control structure command <emph style="italic">control::do</emph> fails to evaluate <emph style="italic">return -code error</emph> in such a way that it acts the same as if <emph style="italic">return -code error</emph> was evaluated directly within proc <emph style="italic">b</emph>.</para>
</section>
<section title="Analysis">
<para>There are two deficiencies in Tcl&apos;s built-in commands that lead to this incapacity in control structure commands defined by <emph style="italic">proc</emph>.</para>
<para>First, <emph style="italic">catch</emph> is not able to capture the information. Consider:</para>
<verbatim><vline encoding='base64'>ICAgJSAgc2V0IGNvZGUgW2NhdGNoIHs=</vline><vline encoding='base64'>ICAgICAgICAgIHJldHVybiAtY29kZSBlcnJvciAtZXJyb3JpbmZvIGZvbyAtZXJyb3Jjb2RlIGJhciBiYXo=</vline><vline encoding='base64'>ICAgICAgfSBtZXNzYWdlXQ==</vline></verbatim>
<para>After evaluation, <emph style="italic">code</emph> contains &quot;2&quot; (<emph style="italic">TCL_RETURN</emph>), and <emph style="italic">message</emph> contains &quot;baz&quot;, but the other values are locked away in internal fields of the <emph style="italic">Tcl_Interp</emph> structure as <emph style="italic">interp-&gt;returnCode</emph>, <emph style="italic">interp-&gt;errorCode</emph>, and <emph style="italic">interp-&gt;errorInfo</emph>. The &quot;-errorcode&quot; and &quot;-errorinfo&quot; values will be copied to the global variables &quot;::errorCode&quot; and &quot;::errorInfo&quot;, respectively, but there will be no way at the script level to get at the <emph style="italic">interp-&gt;returnCode</emph> value which was the value of the original &quot;-code&quot; option.</para>
<para>Second, even if the information were available, there is no built-in command in Tcl that can be evaluated within the body of a proc to make the proc itself act as if it were the command <emph style="italic">return -code</emph>. Stated another way, it is not possible to create a command with <emph style="italic">proc</emph> that behaves exactly the same as <emph style="italic">return -code</emph>. Because of that, it is also not possible to create a command with <emph style="italic">proc</emph> that behaves exactly the same as <emph style="italic">while</emph>, <emph style="italic">if</emph>, etc. - any command that evaluates any of its arguments as a script in the caller&apos;s context.</para>
<para>This is a curious, and likely unintentional, limitation. Tcl goes to great lengths to be sure I can create my own <emph style="italic">break</emph> replacement with <emph style="italic">proc</emph>.</para>
<verbatim><vline encoding='base64'>IHByb2MgbXlCcmVhayB7fSB7cmV0dXJuIC1jb2RlIGJyZWFrfQ==</vline></verbatim>
<para>It would be a welcome completion of Tcl&apos;s set of built-in commands to be able to create a replacement for every one of them using <emph style="italic">proc</emph>.</para>
</section>
<section title="Specification">
<para>The <emph style="italic">return</emph> command shall have syntax:</para>
<verbatim><vline encoding='base64'>IHJldHVybiA/b3B0aW9uIHZhbHVlIC4uLj8gP3Jlc3VsdD8=</vline></verbatim>
<para>There can be any number of <emph style="italic">option value</emph> pairs, and any value at all is acceptable for an <emph style="italic">option</emph> argument. The legal values of a <emph style="italic">value</emph> argument are limited for some <emph style="italic">option</emph>s, as follows:</para>
<quote>the <emph style="italic">value</emph> after a &quot;-code&quot; must be either an integer (32-bit only), or one of the strings, &quot;ok&quot;, &quot;error&quot;, &quot;return&quot;, &quot;break&quot;, or &quot;continue&quot;, just as in the 8.4 spec for <emph style="italic">return</emph>. The default <emph style="italic">value</emph> for the &quot;-code&quot; option is &quot;0&quot;.</quote>
<quote>the <emph style="italic">value</emph> after a &quot;-level&quot; must be a non-negative integer. The default <emph style="italic">value</emph> for the &quot;-level&quot; option is &quot;1&quot;.</quote>
<quote>the <emph style="italic">value</emph> after a &quot;-options&quot; must be a dictionary (<tipref type="text" tip="111"/>). The default <emph style="italic">value</emph> for the &quot;-options&quot; option is an empty dictionary.</quote>
<para>The keys and values in the dictionary <emph style="italic">value</emph> of the &quot;-options&quot; option are pulled out and treated as additional <emph style="italic">option value</emph> arguments to the <emph style="italic">return</emph> command. Note that this &quot;-options&quot; option for option expansion is offered only because Tcl itself has no syntax for argument expansion, as observed many, many times before (for example, <tipref type="text" tip="103"/>).</para>
<para>The <emph style="italic">result</emph> argument, if any, is stored in the interp as the result of the <emph style="italic">return</emph> command. In default operation, this becomes the result of the procedure in which the <emph style="italic">return</emph> command is evaluated.</para>
<para>The return code of the <emph style="italic">return</emph> command is determined by the <emph style="italic">value</emph>s of the &quot;-code&quot; and &quot;-level&quot; options. If the <emph style="italic">value</emph> of the &quot;-level&quot; option is non-zero, then the return code of <emph style="italic">return</emph> is TCL_RETURN. If the <emph style="italic">value</emph> of the &quot;-level&quot; option is &quot;0&quot;, then the return code of <emph style="italic">return</emph> is the <emph style="italic">value</emph> of the &quot;-code&quot; option, translated from string, as needed. In this way,</para>
<verbatim><vline encoding='base64'>IHJldHVybiAtbGV2ZWwgMCAtY29kZSBicmVhaw==</vline></verbatim>
<para>is a synonym for</para>
<verbatim><vline encoding='base64'>IGJyZWFr</vline></verbatim>
<para>while</para>
<verbatim><vline encoding='base64'>IHJldHVybiAtY29kZSBicmVhaw==</vline></verbatim>
<para>spelled out with defaults filled in as:</para>
<verbatim><vline encoding='base64'>IHJldHVybiAtbGV2ZWwgMSAtY29kZSBicmVhaw==</vline></verbatim>
<para>continues to function as before, causing the procedure in which the <emph style="italic">return</emph> is evaluated to return the TCL_BREAK return code.</para>
<para>All <emph style="italic">option value</emph> arguments to <emph style="italic">return</emph> are stored in a return options dictionary kept in the interp, just as the <emph style="italic">result</emph> argument gets stored in the result of the interp.</para>
<para>The TclUpdateReturnInfo() function is modified, so that each level of procedure returning decrements the value of the &quot;-level&quot; key in the return options dictionary. When the value of the &quot;-level&quot; key reaches &quot;0&quot;, the return code from the current procedure will be the value of the &quot;-code&quot; key in the return options dictionary. Otherwise, the return code of the current procedure will be TCL_RETURN.</para>
<para>In this way,</para>
<verbatim><vline encoding='base64'>IHJldHVybiAtbGV2ZWwgMiAtY29kZSBvaw==</vline></verbatim>
<para>is equivalent to</para>
<verbatim><vline encoding='base64'>IHJldHVybiAtY29kZSByZXR1cm4=</vline></verbatim>
<para>and should (absent some intervening <emph style="italic">catch</emph>) cause a normal return to the caller&apos;s caller. Likewise,</para>
<verbatim><vline encoding='base64'>IHJldHVybiAtbGV2ZWwgMyAtY29kZSBvaw==</vline></verbatim>
<para>would cause a normal return to the caller&apos;s caller&apos;s caller (again absent an intervening <emph style="italic">catch</emph>), something that can&apos;t currently be accomplished.</para>
<para>The <emph style="italic">catch</emph> command shall have syntax:</para>
<verbatim><vline encoding='base64'>IGNhdGNoIHNjcmlwdCA/cmVzdWx0VmFyPyA/b3B0aW9uc1Zhcj8=</vline></verbatim>
<para>The new argument <emph style="italic">optionsVar</emph>, if present, will be the name of a variable in which a dictionary of return options should be stored. The return options stored in that dictionary are exactly those needed so that the evaluation of</para>
<verbatim><vline encoding='base64'>IGNhdGNoICRzY3JpcHQgcmVzdWx0IG9wdGlvbnM=</vline><vline encoding='base64'>IHJldHVybiAtb3B0aW9ucyAkb3B0aW9ucyAkcmVzdWx0</vline></verbatim>
<para>is completely indistinguishable (except for the existence and values of variables &quot;result&quot; and &quot;options&quot;) from the direct evaluation of <emph style="italic">$script</emph> by the interpreter. In particular, any values of the &quot;::errorCode&quot; and &quot;::errorInfo&quot; variables are the same as if there were never a <emph style="italic">catch</emph> in the first place.</para>
<para>In addition, when the result of <emph style="italic">catch</emph> is TCL_ERROR, the value in the <emph style="italic">errorLine</emph> field of the <emph style="italic">Interp</emph> struct will be stored as the value of the &quot;-errorline&quot; key in the return options dictionary.</para>
<para>This specification may seem a bit complex, but it makes possible very simple solutions to the problems posed above.</para>
</section>
<section title="Examples">
<para>First lets revisit the analysis:</para>
<verbatim><vline encoding='base64'>ICAgJSAgc2V0IGNvZGUgW2NhdGNoIHs=</vline><vline encoding='base64'>ICAgICAgICAgIHJldHVybiAtY29kZSBlcnJvciAtZXJyb3JpbmZvIGZvbyAtZXJyb3Jjb2RlIGJhciBiYXo=</vline><vline encoding='base64'>ICAgICAgfSBtZXNzYWdlIG9wdGlvbnNd</vline></verbatim>
<para>After evaluation, <emph style="italic">code</emph> contains &quot;2&quot; (<emph style="italic">TCL_RETURN</emph>), <emph style="italic">message</emph> contains &quot;baz&quot;, and now <emph style="italic">options</emph> contains:</para>
<verbatim><vline encoding='base64'>IC1lcnJvcmNvZGUgYmFyIC1lcnJvcmluZm8gZm9vIC1jb2RlIDEgLWxldmVsIDE=</vline></verbatim>
<para>So, the <emph style="italic">options</emph> variable now contains the information that was previously inaccessible. We can now</para>
<verbatim><vline encoding='base64'>IHJldHVybiAtb3B0aW9ucyAkb3B0aW9ucyAkbWVzc2FnZQ==</vline></verbatim>
<para>to get the same results as if the <emph style="italic">catch</emph> had never been there in the first place.</para>
<para>In 8.4 Tcl, it is not possible to implement a replacement for the <emph style="italic">return</emph> command as a proc. After this proposal, such a replacement is:</para>
<verbatim><vline encoding='base64'>IHByb2MgbXlSZXR1cm4gYXJncyB7</vline><vline encoding='base64'>ICAgICBzZXQgcmVzdWx0ICIi</vline><vline encoding='base64'>ICAgICBpZiB7W2xsZW5ndGggJGFyZ3NdICUgMn0gew==</vline><vline encoding='base64'>ICAgICAgICAgc2V0IHJlc3VsdCBbbGluZGV4ICRhcmdzIGVuZF0=</vline><vline encoding='base64'>ICAgICAgICAgc2V0IGFyZ3MgW2xyYW5nZSAkYXJncyAwIGVuZC0xXQ==</vline><vline encoding='base64'>ICAgICB9</vline><vline encoding='base64'>ICAgICBzZXQgb3B0aW9ucyBbZXZhbCBbbGlzdCBkaWN0IGNyZWF0ZSAtbGV2ZWwgMV0gJGFyZ3Nd</vline><vline encoding='base64'>ICAgICBkaWN0IGluY3Igb3B0aW9ucyAtbGV2ZWw=</vline><vline encoding='base64'>ICAgICByZXR1cm4gLW9wdGlvbnMgJG9wdGlvbnMgJHJlc3VsdA==</vline><vline encoding='base64'>IH0=</vline></verbatim>
<para>In every way <emph style="italic">myReturn</emph> should be an equivalent to <emph style="italic">return</emph>.</para>
<para>The new ability to exactly reproduce stack traces makes a <emph style="italic">catch</emph> of large scripts more attractive. For example, a procedure that allocates some resource, then performs operations, and finally frees the resource before returning. In order to be sure the resource is freed, we must <emph style="italic">catch</emph> any errors that might cause the procedure to return before the freeing of the resource. The solution looks like:</para>
<verbatim><vline encoding='base64'>IHByb2MgZG9Tb21ldGhpbmcge30gew==</vline><vline encoding='base64'>ICAgICBzZXQgcmVzb3VyY2UgW2FsbG9jYXRlXQ==</vline><vline encoding='base64'>ICAgICBjYXRjaCB7</vline><vline encoding='base64'>ICAgICAgICAgICMgQXJiaXRyYXJpbHkgbG9uZyBzY3JpcHQgb2Ygb3BlcmF0aW9ucw==</vline><vline encoding='base64'>ICAgICB9IHJlc3VsdCBvcHRpb25z</vline><vline encoding='base64'>ICAgICBkZWFsbG9jYXRlICRyZXNvdXJjZQ==</vline><vline encoding='base64'>ICAgICByZXR1cm4gLW9wdGlvbnMgJG9wdGlvbnMgJHJlc3VsdA==</vline><vline encoding='base64'>IH0=</vline></verbatim>
<para>With that structure, we are confident the resource is always freed, but any error or exception will be presented to the caller exactly as if it had never been caught in the first place.</para>
<para>Here are two examples of how to use the new features in a control structure proc. The essence of a control structure command is its ability to evaluate a script in the caller&apos;s context, preserving the illusion that no additional stack frame was ever used. So, a proc replacement for <emph style="italic">eval</emph> illustrates the technique.</para>
<para>The first approach assumes one knows the internal details of how the <emph style="italic">uplevel</emph> command adds to the stack trace. This is straightforward, but will require a rewrite if <emph style="italic">uplevel</emph> ever changes how it manipulates the stack trace.</para>
<verbatim><vline encoding='base64'>IHByb2MgbXlFdmFsIHNjcmlwdCB7</vline><vline encoding='base64'>ICAgICBpZiB7W2NhdGNoIHt1cGxldmVsIDEgJHNjcmlwdH0gcmVzdWx0IG9wdGlvbnNdID09IDF9IHs=</vline><vline encoding='base64'>ICAgICAgICAgc2V0IHN0YWNrIFtkaWN0IGdldCAkb3B0aW9ucyAtZXJyb3JpbmZvXQ==</vline><vline encoding='base64'>ICAgICAgICAgcmVnc3ViIHtccytpbnZva2VkIGZyb20gd2l0aGluXHMrInVwbGV2ZWwgMSBcJHNjcmlwdCIkfSAkc3RhY2sge30gc3RhY2s=</vline><vline encoding='base64'>ICAgICAgICAgcmVnc3ViIHtcKCJ1cGxldmVsIiBib2R5IGxpbmUgKFxkKylcKSR9ICRzdGFjayBbc3Vic3QgLW5vYmFja3NsYXNoZXMgXA==</vline><vline encoding='base64'>ICAgICAgICAgICAgICAgICB7KCJbbGluZGV4IFtpbmZvIGxldmVsIDBdIDBdIiBib2R5IGxpbmUgXDEpfV0gc3RhY2s=</vline><vline encoding='base64'>ICAgICAgICAgZGljdCBzZXQgb3B0aW9ucyAtZXJyb3JpbmZvICRzdGFjaw==</vline><vline encoding='base64'>ICAgICB9</vline><vline encoding='base64'>ICAgICBkaWN0IGluY3Igb3B0aW9ucyAtbGV2ZWw=</vline><vline encoding='base64'>ICAgICByZXR1cm4gLW9wdGlvbnMgJG9wdGlvbnMgJHJlc3VsdA==</vline><vline encoding='base64'>IH0=</vline></verbatim>
<para>A second, more robust solution is possible, but requires a bit more context gymnastics.</para>
<verbatim><vline encoding='base64'>IG5hbWVzcGFjZSBldmFsIGNvbnRyb2wgew==</vline><vline encoding='base64'>ICAgICBwcm9jIGV2YWwgc2NyaXB0IHs=</vline><vline encoding='base64'>ICAgICAgICAgdmFyaWFibGUgcmVzdWx0</vline><vline encoding='base64'>ICAgICAgICAgdmFyaWFibGUgb3B0aW9ucw==</vline><vline encoding='base64'>ICAgICAgICAgc2V0IGNvZGUgW3VwbGV2ZWwgMSBc</vline><vline encoding='base64'>ICAgICAgICAgICAgICAgICBbbGlzdCA6OmNhdGNoICRzY3JpcHQgW25hbWVzcGFjZSB3aGljaCAtdmFyaWFibGUgcmVzdWx0XSBc</vline><vline encoding='base64'>ICAgICAgICAgICAgICAgICAgICAgICAgIFtuYW1lc3BhY2Ugd2hpY2ggLXZhcmlhYmxlIG9wdGlvbnNdXV0=</vline><vline encoding='base64'>ICAgICAgICAgaWYgeyRjb2RlID09IDF9IHs=</vline><vline encoding='base64'>ICAgICAgICAgICAgIHNldCBsaW5lIFtkaWN0IGdldCAkb3B0aW9ucyAtZXJyb3JsaW5lXQ==</vline><vline encoding='base64'>ICAgICAgICAgICAgIGRpY3QgYXBwZW5kIG9wdGlvbnMgLWVycm9yaW5mbyBc</vline><vline encoding='base64'>ICAgICAgICAgICAgICAgICAgICAgIlxuICAgIChcIltsaW5kZXggW2luZm8gbGV2ZWwgMF0gMF1cIiBib2R5IGxpbmUgJGxpbmUpIg==</vline><vline encoding='base64'>ICAgICAgICAgfQ==</vline><vline encoding='base64'>ICAgICAgICAgZGljdCBpbmNyIG9wdGlvbnMgLWxldmVs</vline><vline encoding='base64'>ICAgICAgICAgcmV0dXJuIC1vcHRpb25zICRvcHRpb25zICRyZXN1bHQ=</vline><vline encoding='base64'>ICAgICB9</vline><vline encoding='base64'>IH0=</vline></verbatim>
<para>Note that in the second solution we did not have to strip away the contributions of <emph style="italic">uplevel</emph> to the stack trace, because we captured the stack trace before <emph style="italic">uplevel</emph> added anything. Then we could add our own information (drawing in part on the new &quot;-errorline&quot; value available to us now at the script level).</para>
<para>We confirm that either approach solves the original problem:</para>
<verbatim><vline encoding='base64'>ICUgcHJvYyBhIHt9IHtldmFsIHtyZXR1cm4gLWNvZGUgZXJyb3J9fQ==</vline><vline encoding='base64'>ICUgcHJvYyBiIHt9IHtteUV2YWwge3JldHVybiAtY29kZSBlcnJvcn19</vline><vline encoding='base64'>ICUgcHJvYyBjIHt9IHtjb250cm9sOjpldmFsIHtyZXR1cm4gLWNvZGUgZXJyb3J9fQ==</vline><vline encoding='base64'>ICUgY2F0Y2ggYQ==</vline><vline encoding='base64'>IDE=</vline><vline encoding='base64'>ICUgY2F0Y2ggYg==</vline><vline encoding='base64'>IDE=</vline><vline encoding='base64'>ICUgY2F0Y2ggYw==</vline><vline encoding='base64'>IDE=</vline></verbatim>
<para>Finally, the new features make possible a utility command that can be of use to people making simple control structure commands, or doing simple wrapping, where there is no need to augment the stack trace, or to treat any return codes in a special way:</para>
<verbatim><vline encoding='base64'>IG5hbWVzcGFjZSBldmFsIGNvbnRyb2wgew==</vline><vline encoding='base64'>ICAgICBwcm9jIGFzY2FsbGVyIHNjcmlwdCB7</vline><vline encoding='base64'>ICAgICAgICAgaWYge1tpbmZvIGxldmVsXSA8IDJ9IHs=</vline><vline encoding='base64'>ICAgICAgICAgICAgIHJldHVybiAtY29kZSBlcnJvciBc</vline><vline encoding='base64'>ICAgICAgICAgICAgICAgICAgICAgIltsaW5kZXggW2luZm8gbGV2ZWwgMF0gMF0gY2FsbGVkIG91dHNpZGUgYSBwcm9jIg==</vline><vline encoding='base64'>ICAgICAgICAgfQ==</vline><vline encoding='base64'>ICAgICAgICAgdmFyaWFibGUgcmVzdWx0</vline><vline encoding='base64'>ICAgICAgICAgdmFyaWFibGUgb3B0aW9ucw==</vline><vline encoding='base64'>ICAgICAgICAgc2V0IGNvZGUgW3VwbGV2ZWwgMiBc</vline><vline encoding='base64'>ICAgICAgICAgICAgICAgICBbbGlzdCA6OmNhdGNoICRzY3JpcHQgICBbbmFtZXNwYWNlIHdoaWNoIC12YXJpYWJsZSByZXN1bHRdIFw=</vline><vline encoding='base64'>ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbbmFtZXNwYWNlIHdoaWNoIC12YXJpYWJsZSBvcHRpb25zXV1d</vline><vline encoding='base64'>ICAgICAgICAgaWYgeyRjb2RlID09IDB9IHs=</vline><vline encoding='base64'>ICAgICAgICAgICAgIHJldHVybiAkcmVzdWx0</vline><vline encoding='base64'>ICAgICAgICAgfQ==</vline><vline encoding='base64'>ICAgICAgICAgZGljdCBpbmNyIG9wdGlvbnMgLWxldmVsIDI=</vline><vline encoding='base64'>ICAgICAgICAgcmV0dXJuIC1vcHRpb25zICRvcHRpb25zICRyZXN1bHQ=</vline><vline encoding='base64'>ICAgICB9</vline><vline encoding='base64'>IH0=</vline></verbatim>
<para>Within a proc, <emph style="italic">ascaller $script</emph> will take care of all aspects of evaluating <emph style="italic">$script</emph> in the caller context, and exiting as appropriate for all non-TCL_OK return codes.</para>
</section>
<section title="Extensibility">
<para>The <emph style="italic">return -code</emph> command has always accepted any integer value as a valid argument, allowing package and application authors to define their own new return codes as needed by their own control structure commands. Now that <emph style="italic">return</emph> will accept any <emph style="italic">option</emph> argument, and <emph style="italic">catch</emph> can capture all <emph style="italic">option value</emph> argument pairs passed to the caught <emph style="italic">return</emph> command, package and application authors now have the ability to augment their custom return codes with additional data. Some prefix convention should be established to avoid key name conflicts in the return options dictionary.</para>
</section>
<section title="Potential Concerns">
<para>Reviewers of drafts of this TIP wondered whether the new &quot;-level&quot; option to <emph style="italic">return</emph> raised the possibility of trouble with an attempt to return more levels than beyond the top of the call stack. </para>
<para>It should be understood that <emph style="italic">return -level N</emph> does not take any shortcut past the intervening levels. Each level of the call stack gets a TCL_RETURN return code, and a &quot;-level&quot; value, dropping by one each step up the stack. Any level in the stack might choose to <emph style="italic">catch</emph> the TCL_RETURN and treat it as it wishes. This is exactly the way the existing <emph style="italic">return -code return</emph> is handled. Normally, it would cause a normal return to the caller&apos;s caller, but if the caller chooses to &apos;catch&apos; it, then the caller has control.</para>
<para>At the toplevel we run out of callers. Then the question becomes how is a TCL_RETURN code at toplevel handled?</para>
<verbatim><vline encoding='base64'>ICUgcmV0dXJuIC1sZXZlbCAwICAgICAgIDsjIHNhbWUgYXMgYSBUQ0xfT0sgYXQgdG9wbGV2ZWw=</vline><vline encoding='base64'>ICUgcmV0dXJuIC1sZXZlbCAxICAgICAgIDsjIHNhbWUgYXMgW3JldHVybl0=</vline><vline encoding='base64'>ICUgcmV0dXJuIC1sZXZlbCAyICAgICAgIDsjIHNhbWUgYXMgW3JldHVybiAtY29kZSByZXR1cm5d</vline><vline encoding='base64'>IGNvbW1hbmQgcmV0dXJuZWQgYmFkIGNvZGU6IDI=</vline></verbatim>
<para>From the C level, <emph style="italic">Tcl_AllowExceptions()</emph> can be used to modify this toplevel behavior.</para>
<para>The following proc will produce the same results as above, but from any level in the call stack (absent an intervening <emph style="italic">catch</emph>):</para>
<verbatim><vline encoding='base64'>ICUgcHJvYyBlc2NhcGUgbGV2ZWwgew==</vline><vline encoding='base64'>ICAgICAgIHNldCB4IFtpbmZvIGxldmVsXQ==</vline><vline encoding='base64'>ICAgICAgIGluY3IgeCAkbGV2ZWw=</vline><vline encoding='base64'>ICAgICAgIHJldHVybiAtbGV2ZWwgJHg=</vline><vline encoding='base64'>ICAgfQ==</vline><vline encoding='base64'>ICUgZXNjYXBlIDA=</vline><vline encoding='base64'>ICUgZXNjYXBlIDE=</vline><vline encoding='base64'>ICUgZXNjYXBlIDI=</vline><vline encoding='base64'>IGNvbW1hbmQgcmV0dXJuZWQgYmFkIGNvZGU6IDI=</vline></verbatim>
<para>Another concern was whether this proposal gave slave interpreters any new powers over their masters. The return code from evaluation of an untrusted script in a slave interpreter should always be wrapped in a <emph style="italic">catch</emph> already, lest a TCL_ERROR in the script blow the stack. Given that, the only thing this proposal does is give the <emph style="italic">catch</emph> command more information to use to decide how to handle the misbehaving script.</para>
</section>
<section title="Compatibility">
<para>It is the author&apos;s belief that this proposal is completely compatible with prior Tcl 8.X releases. Any error-free script that ran before, should continue to run with the same results. At the C level, only internal changes are made, and no new interfaces are defined. Any extension or embedding C program that sticks to the public stubs interface should see no visible change. </para>
</section>
<section title="Prototype">
<para>This proposal is implemented by Tcl Patch 531640 at SourceForge.</para>
<para>The prototype covers all described functionality, but might be further improved with more substantial bytecompiling of [return].</para>
</section>
<section title="Future considerations">
<para>The main reason the global variables <emph style="italic">::errorInfo</emph> and <emph style="italic">::errorCode</emph> exist is to give the script level access to stack and error code information following the <emph style="italic">catch</emph> of a script that raises an error. After this proposal, the <emph style="italic">catch</emph> command itself provides access to that information, so the global variables are not required. One can imagine deprecating them, asking users of Tcl 8.5 to stop writing code that accesses them. They could still have apparent existence, to satisfy the needs of scripts written for earlier Tcl 8.X releases, by means of read traces. In time, Tcl 9 could either continue the read trace scheme, or not provide these global variables at all.</para>
<para>One part of Tcl itself that currently makes use of the <emph style="italic">::errorCode</emph> and <emph style="italic">::errorInfo</emph> variables is the <emph style="italic">bgerror</emph> command. Currently, <emph style="italic">bgerror</emph> accepts exactly one argument, the error message. To make use of stack or error code information, <emph style="italic">bgerror</emph> must retrieve them from the global variables. The proper values of these global variables are re-set by <emph style="italic">Tcl_BackgroundError()</emph> prior to evaluation of <emph style="italic">bgerror</emph>.</para>
<para>As an alternative, <emph style="italic">Tcl_BackgroundError()</emph> could first attempt to call <emph style="italic">bgerror</emph> with <emph style="italic">two</emph> arguments, first the message, then a dictionary of options. If that call returned TCL_ERROR, then a second attempt could be made with a single message argument. In that way, cleaner <emph style="italic">bgerror</emph> commands that get all data from arguments could be supported, while still keeping support for those <emph style="italic">bgerror</emph> commands that were defined for single argument use.</para>
<para>It has been noted several times that the processing of the value of <emph style="italic">::errorInfo</emph> is rather difficult because it is an arbitrary string with no documented structure. A different, more structured way of representing stack trace information would be an improvement. This proposal does not propose an alternative, but because it offers an extensible dictionary for storing arbitrary return options data, it does provide an infrastructure where such approaches might be tried out.</para>
</section>
<section title="Acknowledgments">
<para>This proposal is a synthesis of ideas from many sources. As best I can recall, major contributions came from Joe English, Andreas Leitgeb, Reinhard Max, and Kevin Kenny. If you like the idea, give them some credit; it you don&apos;t, blame me for combining the ideas badly.</para>
</section>
<section title="See also">
<para>Documentation for tcllib&apos;s control package: <url ref="http://tcllib.sf.net/doc/control.html"/></para>
</section>
<section title="Copyright">
<para>This document has been placed in the public domain.</para>
</section>
</body></TIP>

