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

<TIP number='232'>
<header><title>Creating New Math Functions for the &apos;expr&apos; Command</title><author address="mailto:arjen.markus@wldelft.nl">Arjen Markus</author><author address="mailto:kennykb@acm.org ">Kevin Kenny</author><status type='project' state='final' tclversion="8.5" vote='after'>$Revision: 1.11 $</status><history></history><created day='26' month='nov' year='2004' /><keyword>math expr Tcl</keyword></header>
<abstract>This TIP proposes to replace Tcl&apos;s math functions, ordinarily created using the <emph style="bold">Tcl_CreateMathFunc()</emph> function, with ordinary Tcl commands created in a known namespace, <emph style="bold">::tcl::mathfunc</emph>. This change has two chief motivations: it allows programmers to define new math functions at the Tcl level, and it encapsulates the <emph style="bold">Tcl_Value</emph> API so that new math functions can work on data types that are not described adequately as <emph style="bold">Tcl_Value</emph> objects.</abstract>
<body><section title="Rationale">
<para>The two authors of this TIP, Kevin Kenny and Arjen Markus, have come at wanting the same change to Tcl from two distinct directions.</para>
<para>Arjen Markus has been the maintainer of several modules in Tcllib that implement &quot;special functions&quot; such as the exponential integral, the incomplete gamma function and the Bessel functions. He has wanted to have &quot;scripted&quot; math functions available to simplify his notation. In place of a complex expression like</para>
<verbatim><vline encoding='base64'>ICBzZXQgZiBbZXhwciB7ICR4KltKMCAkeF0gKyBbSjEgW2V4cHIgezIuMCokeH1dXSB9XQ==</vline></verbatim>
<para>which is pretty unreadable (and prone to error because of the need to brace the subexpressions), he would like a mechanism for defining new mathematical functions so that he can write:</para>
<verbatim><vline encoding='base64'>ICBzZXQgZiBbZXhwciB7ICR4KkowKCR4KSArIEoxKDIuMCokeCkgfV0=</vline></verbatim>
<para>Donal Fellows has felt the need for such a construct, too, enough to implement a &quot;funcproc&quot; extension that provides it. [<url ref="http://wiki.tcl.tk/541"/>] </para>
<para>Kevin Kenny has come at the desire for rework of the math function mechanism from a different direction. He has been investigating Tcl Core support for arbitrary-precision integers <tipref type="text" tip="237"/>, and discovered that implementing math functions that accept them as arguments or return them as results would require an incompatible change to the <emph style="bold">Tcl_Value</emph> data type that is used to communicate with the math functions. When the last such change was made (in implementing 64-bit integers <tipref type="text" tip="72"/>), it required a source code change to several popular extensions that created new math functions <emph style="italic">min</emph> and <emph style="italic">max</emph>. Wishing the incompatibility introduced by <tipref type="text" tip="237"/> to be the last of the type, he decided to eliminate <emph style="bold">Tcl_Value</emph> and use the open-ended <emph style="bold">Tcl_Obj</emph> data type in its place. When he derived the type signature that a math function would have if it accepted its parameters in an array of <emph style="bold">Tcl_Obj</emph> pointers, he discovered that it was identical to the <emph style="bold">Tcl_ObjCmdProc</emph> -- making him ask, &quot;what if math functions really <emph style="italic">were</emph> commands?&quot;</para>
<para>This TIP is the result of those two investigations, and proposes a unification of math functions with Tcl commands.</para>
</section>
<section title="Proposed Changes">
<para>This TIP proposes that:</para>
<enumerate><item.e index='1'><para>The [expr] command shall be modified so that an expression of the form:</para><verbatim><vline encoding='base64'>ICAgZihhcmcxLGFyZzIsLi4uKQ==</vline></verbatim><para>shall generate code equivalent to that generated by</para><verbatim><vline encoding='base64'>ICAgW3RjbDo6bWF0aGZ1bmM6OmYgW2V4cHIgeyBhcmcxIH1dIFtleHByIHsgYXJnMiB9XSAuLi5d</vline></verbatim><para>so that math functions are interpreted as Tcl commands whose arguments are parsed as subexpressions. The existing code in [expr] that checks for correct argument counts to the math functions at compile time shall be removed (the general consensus among Core maintainers is that compile-time checks of this sort are a bad idea anyway).</para><para>Note that the call to <emph style="italic">tcl::mathfunc::f</emph> has no leading namespace delimiter. A search for the function will try to resolve it first relative to the current namespace.</para></item.e><item.e index='2'><para>The current math functions in Tcl shall be reimplemented as ordinary Tcl commands in the <emph style="bold">::tcl::mathfunc</emph> namespace; a Tcl interpreter will contain commands <emph style="bold">::tcl::mathfunc::abs</emph>, <emph style="bold">::tcl::mathfunc::acos</emph>, etc. </para></item.e><item.e index='3'><para>The Tcl command [info functions] shall be deprecated in favor of searching for math functions using [info commands] in the appropriate namespace.</para></item.e><item.e index='4'><para>The C functions <emph style="bold">Tcl_CreateMathFunc</emph>, <emph style="bold">Tcl_GetMathFuncInfo</emph>, and <emph style="bold">Tcl_ListMathFuncs</emph> shall be deprecated in favor of <emph style="bold">Tcl_CreateObjCommand</emph>, <emph style="bold">Tcl_GetCommandInfo</emph> and [info commands]. (The last is provided only in Tcl at the present time; we do not export a C-level interface to enumerate commands in a namespace.) The functions will continue to work for extensions that use them. The <emph style="bold">Tcl_CreateMathFunc</emph> command will create a Tcl command in the <emph style="bold">::tcl::mathfunc</emph> namespace whose command procedure checks argument count and types and dispatches to the math function handler. The <emph style="bold">Tcl_GetMathFuncInfo</emph> procedure will return <emph style="italic">TCL_OK</emph> or <emph style="italic">TCL_ERROR</emph> according to whether the given math function exists in <emph style="bold">::tcl::mathfunc</emph> and will return parameter information for (only) those functions defined using <emph style="bold">Tcl_CreateMathFunc</emph>. Functions defined as ordinary Tcl commands shall return <emph style="italic">TCL_OK</emph> but have a parameter count of -1. The <emph style="bold">Tcl_ListMathFuncs</emph> procedure will simply enumerate all the commands in the <emph style="bold">::tcl::mathfunc</emph> namespace.</para></item.e><item.e index='5'><para>Several error messages change as a side effect of changing the math function implementation. All of the new messages are more informative than the old ones (for instance, identifying which math function encountered a parameter error rather than a generic &quot;too few/too many arguments to math function&quot;), with the exception of the error message for an unknown function, which is replaced with &quot;unknown command ::tcl::mathfunc::&lt;the_command&gt;&quot; where &lt;the_command&gt; is the name of the missing function.</para></item.e></enumerate>
</section>
<section title="Discussion">
<para>The proposed change lifts several other restrictions in the way math functions operate:</para>
<enumerate><item.e index='1'><para>There is no longer any restriction that new math functions must accept a fixed number of arguments, or, indeed, that their arguments and results must be numeric. It will be possible to create variadic functions like:</para><verbatim><vline encoding='base64'>ICAgcHJvYyA6OnRjbDo6bWF0aGZ1bmM6Om1pbiBhcmdzIHs=</vline><vline encoding='base64'>ICAgICAgIHNldCBtIEluZg==</vline><vline encoding='base64'>ICAgICAgIGZvcmVhY2ggYSAkYXJncyB7</vline><vline encoding='base64'>ICAgICAgICAgICBpZiB7ICRhIDwgJG0gfSB7</vline><vline encoding='base64'>ICAgICAgICAgICAgICAgc2V0IG0gJGE=</vline><vline encoding='base64'>ICAgICAgICAgICB9</vline><vline encoding='base64'>ICAgICAgIH0=</vline><vline encoding='base64'>ICAgICAgIHJldHVybiAkbQ==</vline><vline encoding='base64'>ICAgfQ==</vline></verbatim></item.e><item.e index='2'><para>It will be possible to compile Tcl code that refers to a math function that has not yet been defined. That is:</para><verbatim><vline encoding='base64'>ICAgcHJvYyBmb28geyB4IH0gew==</vline><vline encoding='base64'>ICAgICAgIHNldCBoYXZlX2YgW2xsZW5ndGggW2luZm8gY29tbWFuZHMgOjp0Y2w6Om1hdGhmdW5jOjpmXV0=</vline><vline encoding='base64'>ICAgICAgIGlmIHsgJGhhdmVfZiB9IHs=</vline><vline encoding='base64'>ICAgICAgICAgICByZXR1cm4gW2V4cHIgeyBmKCR4KSB9XQ==</vline><vline encoding='base64'>ICAgICAgIH0gZWxzZSB7</vline><vline encoding='base64'>ICAgICAgICAgICAuLi4gZmFsbGJhY2sgLi4u</vline><vline encoding='base64'>ICAgICAgIH0=</vline><vline encoding='base64'>ICAgfQ==</vline></verbatim><para>will be a valid procedure. (In Tcl 8.4, the procedure will fail to compile if <emph style="italic">f</emph> is not known at compile time, something that runs contrary to the dynamic nature of Tcl.)</para></item.e><item.e index='3'><para>Namespaces will be able to define their own math functions that are not visible outside those namespaces. If a namespace defines a function <emph style="bold">[namespace current]::tcl::mathfunc::f</emph>, then calls to <emph style="bold">f</emph> in expressions evaluated in that namespace will resolve to it in preference to <emph style="bold">::tcl::mathfunc::f</emph>. Not only does this rule allow two extensions both to define functions <emph style="bold">f</emph> without collision, but it also allows an extension to override a builtin function such as <emph style="bold">sin</emph>.</para></item.e></enumerate>
<para>Alas, all these improvements come at some cost of performance. On Kevin Kenny&apos;s machine, the command</para>
<verbatim><vline encoding='base64'>IGV4cHIge3NpbigwLjMyNSl9</vline></verbatim>
<para>executes in roughly 520 nanoseconds before the change, and 870 nanoseconds afterward. Since the resolution of the function name is cached, name lookup is not the problem; rather, the issue is that invoking the function as a command needs to look for command traces; this whole mechanism costs about 300-350 ns (and has been observed to do so in other contexts). For real-life expressions, the additional cost tends to vanish quickly into statistical noise; variable access (with corresponding checks for traces) and bytecode overhead quickly comes to dominate the performance for all but the simplest expressions.</para>
</section>
<section title="Safe Interpreters">
<para>It is not anticipated that exposing this functionality in a safe interpreter will present any new problems for safety. Any functionality that the interpreter can access by defining or overriding math functions is functionality that would have been available to it by calling the functions as commands.</para>
</section>
<section title="Impact on C-coded Extensions">
<para>Extensions coded in C that wish to create math functions accepting parameters of type <emph style="bold">TCL_EITHER</emph> may find that they do not get type coercion from parameters of new numeric types, such as extended-precision integers. The coding change to replace them with Tcl commands is fairly easy and mechanical, at a level of effort comparable to that needed for <tipref type="text" tip="72"/>. Moreover, once it is completed, a math function will be using the known <emph style="bold">Tcl_CreateObjCmd</emph> API, which has been stable since Tcl 8.0 and is unlikely to change substantially in future releases.</para>
<para>The <emph style="italic">tbcload</emph> extension will need to implement a small amount of bytecode translation to preserve compatibility with bytecode compiled modules built against earlier versions of Tcl. The reason is that two bytecodes, <emph style="bold">INST_INVOKE_BUILTIN1</emph> and <emph style="bold">INST_INVOKE_FUNC1</emph> have been eliminated from <emph style="bold">Tcl_ExecuteByteCode</emph> since the compiler no longer emits them. If this change for some reason should prove infeasible, we can always put the bytecodes back into <emph style="bold">Tcl_ExecuteByteCode</emph>, but the authors of this TIP would prefer to avoid the code bloat.</para>
</section>
<section title="Reference Implementation">
<para>A reference implementation is committed on the &apos;tcl-numerics-branch&apos; at SourceForge and may be retrieved with</para>
<verbatim><vline encoding='base64'>IGN2cyAtZDpleHQ6VVNFUklEQGN2cy5zb3VyY2Vmb3JnZS5uZXQ6L2N2c3Jvb3QvdGNsIGNoZWNrb3V0IC1yVElQMjMyIHRjbF9udW1lcmljcw==</vline></verbatim>
</section>
<section title="Copyright">
<para>Copyright (c) 2005 by Kevin B. Kenny and Adriaan Markus. All rights reserved.</para>
<para>This document may be distributed subject to the terms and conditions set forth in the Open Publication License, version 1.0 [<url ref="http://www.opencontent.org/openpub/"/>].</para>
</section>
</body></TIP>
