<!DOCTYPE html>
<html>
<head>
<title>nxproc-doc.md</title>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
<style>
/* https://github.com/microsoft/vscode/blob/master/extensions/markdown-language-features/media/markdown.css */
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
body {
font-family: var(--vscode-markdown-font-family, -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", "Ubuntu", "Droid Sans", sans-serif);
font-size: var(--vscode-markdown-font-size, 14px);
padding: 0 26px;
line-height: var(--vscode-markdown-line-height, 22px);
word-wrap: break-word;
}
#code-csp-warning {
position: fixed;
top: 0;
right: 0;
color: white;
margin: 16px;
text-align: center;
font-size: 12px;
font-family: sans-serif;
background-color:#444444;
cursor: pointer;
padding: 6px;
box-shadow: 1px 1px 1px rgba(0,0,0,.25);
}
#code-csp-warning:hover {
text-decoration: none;
background-color:#007acc;
box-shadow: 2px 2px 2px rgba(0,0,0,.25);
}
body.scrollBeyondLastLine {
margin-bottom: calc(100vh - 22px);
}
body.showEditorSelection .code-line {
position: relative;
}
body.showEditorSelection .code-active-line:before,
body.showEditorSelection .code-line:hover:before {
content: "";
display: block;
position: absolute;
top: 0;
left: -12px;
height: 100%;
}
body.showEditorSelection li.code-active-line:before,
body.showEditorSelection li.code-line:hover:before {
left: -30px;
}
.vscode-light.showEditorSelection .code-active-line:before {
border-left: 3px solid rgba(0, 0, 0, 0.15);
}
.vscode-light.showEditorSelection .code-line:hover:before {
border-left: 3px solid rgba(0, 0, 0, 0.40);
}
.vscode-light.showEditorSelection .code-line .code-line:hover:before {
border-left: none;
}
.vscode-dark.showEditorSelection .code-active-line:before {
border-left: 3px solid rgba(255, 255, 255, 0.4);
}
.vscode-dark.showEditorSelection .code-line:hover:before {
border-left: 3px solid rgba(255, 255, 255, 0.60);
}
.vscode-dark.showEditorSelection .code-line .code-line:hover:before {
border-left: none;
}
.vscode-high-contrast.showEditorSelection .code-active-line:before {
border-left: 3px solid rgba(255, 160, 0, 0.7);
}
.vscode-high-contrast.showEditorSelection .code-line:hover:before {
border-left: 3px solid rgba(255, 160, 0, 1);
}
.vscode-high-contrast.showEditorSelection .code-line .code-line:hover:before {
border-left: none;
}
img {
max-width: 100%;
max-height: 100%;
}
a {
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
a:focus,
input:focus,
select:focus,
textarea:focus {
outline: 1px solid -webkit-focus-ring-color;
outline-offset: -1px;
}
hr {
border: 0;
height: 2px;
border-bottom: 2px solid;
}
h1 {
padding-bottom: 0.3em;
line-height: 1.2;
border-bottom-width: 1px;
border-bottom-style: solid;
}
h1, h2, h3 {
font-weight: normal;
}
table {
border-collapse: collapse;
}
table > thead > tr > th {
text-align: left;
border-bottom: 1px solid;
}
table > thead > tr > th,
table > thead > tr > td,
table > tbody > tr > th,
table > tbody > tr > td {
padding: 5px 10px;
}
table > tbody > tr + tr > td {
border-top: 1px solid;
}
blockquote {
margin: 0 7px 0 5px;
padding: 0 16px 0 10px;
border-left-width: 5px;
border-left-style: solid;
}
code {
font-family: Menlo, Monaco, Consolas, "Droid Sans Mono", "Courier New", monospace, "Droid Sans Fallback";
font-size: 1em;
line-height: 1.357em;
}
body.wordWrap pre {
white-space: pre-wrap;
}
pre:not(.hljs),
pre.hljs code > div {
padding: 16px;
border-radius: 3px;
overflow: auto;
}
pre code {
color: var(--vscode-editor-foreground);
tab-size: 4;
}
/** Theming */
.vscode-light pre {
background-color: rgba(220, 220, 220, 0.4);
}
.vscode-dark pre {
background-color: rgba(10, 10, 10, 0.4);
}
.vscode-high-contrast pre {
background-color: rgb(0, 0, 0);
}
.vscode-high-contrast h1 {
border-color: rgb(0, 0, 0);
}
.vscode-light table > thead > tr > th {
border-color: rgba(0, 0, 0, 0.69);
}
.vscode-dark table > thead > tr > th {
border-color: rgba(255, 255, 255, 0.69);
}
.vscode-light h1,
.vscode-light hr,
.vscode-light table > tbody > tr + tr > td {
border-color: rgba(0, 0, 0, 0.18);
}
.vscode-dark h1,
.vscode-dark hr,
.vscode-dark table > tbody > tr + tr > td {
border-color: rgba(255, 255, 255, 0.18);
}
</style>
<style>
/* Tomorrow Theme */
/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */
/* Original theme - https://github.com/chriskempson/tomorrow-theme */
/* Tomorrow Comment */
.hljs-comment,
.hljs-quote {
color: #8e908c;
}
/* Tomorrow Red */
.hljs-variable,
.hljs-template-variable,
.hljs-tag,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class,
.hljs-regexp,
.hljs-deletion {
color: #c82829;
}
/* Tomorrow Orange */
.hljs-number,
.hljs-built_in,
.hljs-builtin-name,
.hljs-literal,
.hljs-type,
.hljs-params,
.hljs-meta,
.hljs-link {
color: #f5871f;
}
/* Tomorrow Yellow */
.hljs-attribute {
color: #eab700;
}
/* Tomorrow Green */
.hljs-string,
.hljs-symbol,
.hljs-bullet,
.hljs-addition {
color: #718c00;
}
/* Tomorrow Blue */
.hljs-title,
.hljs-section {
color: #4271ae;
}
/* Tomorrow Purple */
.hljs-keyword,
.hljs-selector-tag {
color: #8959a8;
}
.hljs {
display: block;
overflow-x: auto;
color: #4d4d4c;
padding: 0.5em;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}
</style>
<style>
/*
* Markdown PDF CSS
*/
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", "Ubuntu", "Droid Sans", sans-serif, "Meiryo";
padding: 0 12px;
}
pre {
background-color: #f8f8f8;
border: 1px solid #cccccc;
border-radius: 3px;
overflow-x: auto;
white-space: pre-wrap;
overflow-wrap: break-word;
}
pre:not(.hljs) {
padding: 23px;
line-height: 19px;
}
blockquote {
background: rgba(127, 127, 127, 0.1);
border-color: rgba(0, 122, 204, 0.5);
}
.emoji {
height: 1.4em;
}
code {
font-size: 14px;
line-height: 19px;
}
/* for inline code */
:not(pre):not(.hljs) > code {
color: #C9AE75; /* Change the old color so it seems less like an error */
font-size: inherit;
}
/* Page Break : use <div class="page"/> to insert page break
-------------------------------------------------------- */
.page {
page-break-after: always;
}
</style>
<script src="https://unpkg.com/mermaid/dist/mermaid.min.js"></script>
</head>
<body>
<script>
mermaid.initialize({
startOnLoad: true,
theme: document.body.classList.contains('vscode-dark') || document.body.classList.contains('vscode-high-contrast')
? 'dark'
: 'default'
});
</script>
<!-- nxproc-doc.md -->
<!-- rev1.1.0 Thu 4 Jan 2024 21:02:34 -08:00 -->
<!-- rev1.1.1 Sun 7 Jan 2024 18:45:59 -08:00 -->
<!-- rev1.1.2 Sun 14 Jan 2024 23:28:09 -08:00 -->
<h1 id="nxproc"><strong>nxproc</strong></h1>
<h1 id="overview"><em><strong>Overview</strong></em></h1>
<p><strong>nxproc</strong> is a Tcl extention enhancing user-defined procedures with <em>n</em>amed-argument synta<em>x</em> similar to many Tcl built-in commands. The extension provides 6 <em>proc</em>-like commands: <em>nxproc</em>, <em>nxconstructor</em>, <em>nxmethod</em> and <em>-ci</em> variations.</p>
<p><em>nxproc</em> procedures are very close to "drop-in compatible" replacements for Tcl <em>proc</em>, <em>method</em> and <em>constructor</em> commands. This document describes syntax and features of the new commands as well as differences from Tcl built-in commands.</p>
<h1 id="installation"><em><strong>Installation</strong></em></h1>
<h2 id="download"><strong>Download</strong></h2>
<p>Main repository: https://thinairarts.com/fossil/nxproc<br>
Download: https://thinairarts.com/fossil/nxproc/download</p>
<p>Available in formats: tgz, zip</p>
<h2 id="install-to-appropriate-directory"><strong>Install to appropriate directory</strong></h2>
<p>Once downloaded, decompress the archive in any convenient directory. Copy the nxproc1.0 directory to a location on the Tcl package path. (Usually */lib in the Tcl installation location.) Binaries are included for unix and Windows under tcl8 and tcl9 directories. (The supplied binaries were compiled for Tcl8.7 and 9.0. Using with Tcl8.6.11+ is supported. Recompiling for older Tcl versions will be necessary.)</p>
<h2 id="compiling-from-source"><strong>Compiling from source</strong></h2>
<p>Full source code is included (in the ./generic directory). Compiling is straightforward. Configuration uses the configdef system. (Consult the configdef project documentation for more information.) Binaries (<em>config</em> and <em>genPkgIndex</em> are available in the ./bin directory.) Copying the runnable programs to location like <em>/usr/local/bin</em> assures availability.</p>
<p>Configuring for a given system requires modifying config.def in the target directory (<em>i.e.</em>, unix/tcl8, etc.) with the path to installed Tcl location, desired nxproc installation directories, and other details. Alternatively, configuration parameters can be specified on the <em>config</em> command line. This is particularly useful as a one-time option, <em>e.g.</em>, generating a profiling-enabled binary.</p>
<p>After modifying config.def it's only necessary to run <em>config</em> in the directory to generate the Makefile. Run "make && make install". nxproc should then be installed in the preselected Tcl installations and can be used with those versions of Tcl.</p>
<h1 id="nxproc-usage"><strong><em>nxproc</em> usage</strong></h1>
<p>Since the new commands introduced by this project have for the most part identical syntax and features, they'll be referred to collectively as "<em>nxproc</em>" throughout this document. Relevant differences among them will be made clear.</p>
<h2 id="general-syntax"><strong>General syntax</strong></h2>
<p>Include <code>package require nxproc</code> in files where <em>nxproc</em> commands are used.</p>
<p>Syntax largely follows the conventions of Tcl <em>proc</em> command:</p>
<pre><code>nxproc <proc name> {?fixed args? ?named args? ?**?} {
<body>
}
</code></pre>
<p>Differences in arguments are described below. <em>Proc name</em> and <em>body</em> follow standard <em>proc</em> rules.</p>
<h2 id="object-oriented-procedures"><strong>Object-oriented procedures</strong></h2>
<p>The package provides <em>nxconstructor</em> and <em>nxmethod</em>. Differences in syntax vs. <em>nxproc</em> are minimal, but share semantics. In total, the package adds 6 new procedures, <em>nxproc</em>, <em>nxconstructor</em>, <em>nxmethod</em> and their <em>-ci</em> variants.</p>
<h2 id="nxproc-arguments"><strong><em>nxproc</em> arguments</strong></h2>
<p><em>nxproc</em> procedures allow 4 kinds of input arguments: fixed, named-args, <em>nxargs</em> and <em>nxunknown</em>.</p>
<p>Fixed (positional) arguments are just like "regular" <em>proc</em> arguments, including the recent addition of optional defaults. Without defaults, fixed parameters are mandatory when the command is called:</p>
<pre><code>% nxproc myproc {a b} {return "$a, $b"}
% myproc cat dog
cat, dog
% myproc cat
"Error: Missing value: arg 2 ('b')."
% myproc cat dog antelope
"Error: Expected '-' first char: antelope"
</code></pre>
<p>There are two styles of <em>named arguments</em>:</p>
<ul>
<li>
<p><code> <name> <value></code>, or <code><name> <type designator> <value></code>.</p>
</li>
<li>
<p>Named argument names must be have a leading '-' character.</p>
</li>
<li>
<p>A <em>type designator</em> is one of the following:</p>
<ul>
<li><strong>str</strong> (string),</li>
<li><strong>num</strong> (numeric),</li>
<li><strong>bool</strong> (boolean),</li>
<li><strong>enum</strong> (enumerated).</li>
<li>A one character abbreviation is adequate: <strong>s</strong>, <strong>n</strong>, <strong>b</strong> or <strong>e</strong> respectively.</li>
</ul>
</li>
<li>
<p>Last part is the <em>value</em>. The type of the value has to agree with the type designator.</p>
</li>
</ul>
<p>Note that type designators are <em>not</em> case sensitive, so "e", "E", "enum" and "ENUM" are all equivalent.</p>
<p>For string and numeric arguments, when a type designator isn't given, type is inferred as <em>str</em> or <em>num</em>. A type designator must be supplied for proper operation on <em>bool</em> and <em>enum</em> arguments. For their intended purpose, boolean values are restricted to the set of (0,1). However Tcl doesn't distinguish between boolean and general numeric values. A type designator is necessary to disambiguate the intended boolean from numeric values.</p>
<p>Enumerated values are lists. In Tcl at the script level lists and strings are not distinct. The type designator assures enumerated values are handled propely.</p>
<p>Consider these examples:</p>
<pre><code># implicit string
% nxproc p0 {-var0 cat} {
return "v0==$var0"
}
% p0 -var0 dog
v0==dog
# implicit number
% nxproc p1 {-var1 32} {
return "v1==[+ $var1 10]"
}
% p1 -var1 120
v1==130
# explicit boolean
% nxproc p2 {-var2 b 0} {
return "v2==$var2
}
% p2 -var2
v2==1
# explicit enum
% nxproc p3 {-var3 enum {cat dog bear cow}} {
return "v3==$var3"
}
% p3
v3==cat
% p3 -var3 bear
v3==bear
% p3 -var3 giraffe
Error: Value 'giraffe' is not a member of enum 'var3'.
# no type designator (e, enum)
% nxproc p4 {-var4 {cat dog bear cow}} {
return "v4==$var4"
}
% p4
v4==cat dog bear cow ;# that is, p4 is a string...
</code></pre>
<p><em>nxproc</em> also checks on argument type when <em>nxproc</em> is invoked and issues an error if (bool, numeric) types and values don't match:</p>
<pre><code>% nxproc p5 {-var5 NUM 54x} {
return "v5==$var5"
}
Error: <nxproc p5> '-var5': '54x' is not numeric.
</code></pre>
<div style="page-break-after: always"></div>
<p>Also, if items are missing nxproc signals an error:</p>
<pre><code>% nxproc p5 {-var5 54 var6 "OK" } {
return "v5==$var5, v6==$var6"
}
Error: <nxproc p5> 'var6'=malformed option. (Should be -var6)
% nxproc p6 {-var6 "Hello!" -var7 b } {
return "v6==$var6, v7==$var7
}
Error: <nxproc p6> missing value (pos 4, after '-var7')
</code></pre>
<p>The final kind of argument is similar to "args" in <em>proc</em>. (Note that this kind of argument is valid when <em>calling</em> a created command, not when <em>nxproc</em> is <em>creating</em> commands.)</p>
<p>The nxargs feature collects all input after "-->, "--" or "->" appear on the command line.</p>
<pre><code># use nxproc to create myproc...call myproc...
myproc -abc abc -cde cde --> fgh ijk
# Everything after --> is collected in nxargs as a list...
puts $nxargs
# -> fgh ijk
</code></pre>
<p>Another example:</p>
<pre><code># create command (p7)
% nxproc p7 {a b -var8 "a string value"} {
return "$a, $b, $var8, nxargs {$nxargs}"
}
# call p7, -->, -- or -> marks end of arguments
% p7 one two -var8 "more stuff" --> filename.tcl something.else
one, two, more stuff, nxargs {filename.tcl something.else}
</code></pre>
<p>Finally, <em>nxproc</em> procedures can also handle unexpected arguments using the "two-star" or <em>**</em> option. Including ** in the list of formals signifies that all unknown arguments and values will be available as a list in the procedure body variable <em>nxunkown</em>. When ** is included, no error is signaled due to unknown options/values entered on the command line.</p>
<pre><code>% nxproc myproc {-abc a -cde b **} {
puts "nxunknown == $nxunknown"
}
# then ...
% myproc -abc abc MM OO PP -cde cde -XYZ XY" --> qrs tuv
# note that "MM OO PP" and "-XYZ XYZ" aren't known to myproc
nxunknown == MM OO PP -XYZ XYZ
</code></pre>
<p>The <em>nxunknown</em> mechanism applies to the command line after fixed args. Since fixed arg input is terminated by the first "-xxx" appearing on the command line, it represents the first possible unknown argument.</p>
<pre><code>% nxproc myproc {{a 192} {b wolf} **} {
puts "$a, $b, && $nxunkown"
}
% myproc 444 -nothing important
444, wolf, && -nothing important
</code></pre>
<p>While <em>nxproc</em> does not have the standard "args" variable, it does provide these two args-like variables. In some ways they even extend the args idea, especially <em>nxunknown</em> which collects all unknown args regardless of placement.
The nxunknown facility can be quite useful, for example constructing oo::class hierarchies.</p>
<p><em>nxproc</em> checks numeric, boolean and enum values at creation and runtime:</p>
<pre><code>% nxproc numproc {-numitem 88} {return $numitem}
% numproc -numitem 8b
Error: Option -numitem: value is not a number.
% nxproc boolproc {-boolitm b 0} {return $boolitm}
% boolproc -boolitm 10
Error: Option -boolitm: '10' not boolean value
% nxproc enumproc {-enumitm e {abc cde fgh}} {return $enumitm}
% enumproc -enumitm ijk
Error: Value 'ijk' is not a member of enum 'enumitm'.
</code></pre>
<div style="page-break-after: always"></div>
<p>Default variables and values are printed to the terminal when "-?" or "-opt" is the argument to an <em>nxproc</em> procedure:</p>
<pre><code>% source procx-test.tcl
% all -?
_____ bool ____
flagd: 0
flagx: 0
flagc: 1
flagy: 1
_____ str _____
kitchen: modern stuff
floors: linoleum
walls: off-white
auto: Honda
_____ num _____
frac: 0.5
area: 2000
rooms: 12
doors: 4
_____ enum ____
critter: cat dog racoon deer ants birds
food: vegetable fruit meat legume grain
</code></pre>
<h2 id="the-nxproc-ci-command"><strong>The <em>nxproc-ci</em> command</strong></h2>
<p>The <em>nxproc-ci</em> command is identical to <em>nxproc</em> except allowing named arguments to be called as upper or lower case (or any combination thereof). This can be convenient under some conditions.</p>
<pre><code>nxproc-ci p1 {-person_name "name" -address "address"} {
...
puts "$person_name"
puts "$address"
...
}
p1 -Person_Name "Tom Thumb" -ADDRESS "111 Main Street"
Tom Thumb
111 Main Street
</code></pre>
<p>Note that in the procedure body <em>variable names</em> match exactly what was given to <em>nxprox-ci</em> (minus the leading dash). In the example, the body's variables are "person_name" and "address". The variable names are <em>not</em> altered or affected by the case of the command line arguments.</p>
<h2 id="nxconstructor-and-nxmethod"><strong>nxconstructor and nxmethod</strong></h2>
<p>These procedures replace <em>constructor</em> and <em>method</em> in TclOO code. Except for <em>nx-</em> specific features, syntax is essentially the same as the native procedures.</p>
<pre><code>oo::class create MyClass {
...
nxconstructor {-name ...} { ... }
nxmethod methodname {-arg0 val0 ...} { ... }
}
</code></pre>
<p>Previously described <em>nx...</em> patterns apply to <em>nxconstructor</em>/<em>nxmethod</em>. All features including -->/--/-> and ** are available and arguably even more useful in the TclOO environment. The full range of TclOO facilities are available to <em>nx...</em> procedures.</p>
<h2 id="the-dtype-command"><strong>The <em>dtype</em> command</strong></h2>
<p><em>nxproc</em> provides the <em>dtype</em> command which returns the nxproc type assigned to a variable when the procedure was created.</p>
<pre><code># dtype ?-n? <varname>
# returns string value of type: bool, num, str or enum
# with -n, returns numeric value: 101-104
</code></pre>
<h1 id="profiling"><strong>Profiling</strong></h1>
<p><em>nxproc</em> can be compiled to activate profiling. This is accomplished by adding -DPROFILE to "DEFS" in the Makefile. This is handled in config.def by defining a Default value for "profile" as "1". Setting to "0" disables profiling.</p>
<p>(When profiling is turned off, profiling code has absolutely no effect on program behavior or performance. It's only compiled into the extension when intentionally activated.)</p>
<p>Profiling works by timing certain parts of the running program. Namely, it measures time required for handling fixed parameters, time needed for default variables, and time used to process command line options. Not only is the absolute time of each function important but also the ratio among them.</p>
<p>Running profile-enabled <em>nxproc</em> is most easily accomplished using the "prof" command from "nxtest.tcl" (in the "test" directory). It can be accessed through "procx-test.tcl", which has numerous test procedures already set up and ready to use. "prof" itself is created by <em>nxproc</em>.</p>
<p>The <em>procdata</em> command is a companion to <em>nxproc</em>. When a Tcl interpreter has used "package require nxproc", <em>procdata</em> is also available:</p>
<pre><code>$ cd /path/to/procx/test
$ /usr/local/opt/tcl87b1s
% source procx-test.tcl
% procdata
currProcRec 27, lenprocx 30
prof prof__2061f0__ 482 -
test test__fe9b0__ 1085 -
ts ts__4fa0d8__ 136 -
tsA tsA__b3c6c__ 136 -
filter filter__7d01a9__ 329 -
filterA filterA__8b571c__ 329 CI
...
</code></pre>
<p>Without arguments <em>procdata</em> prints info about procedures created using <em>nxproc</em>. First column is the procedure name, followed by internal name, length (bytes) of procedure body. CI indicates procedure arguments are case-insensitive. When profiling is active <em>procdata</em> takes additional arguments that affect profile results. These arguments are handled by "prof".</p>
<pre><code># prof syntax:
# prof <arguments>
# <name of procedure to profile> (string, required)
# -samples (integer, default: 500000, optional)
# -record (boolean, default: 0, optional) (save all data points)
# -cmdln (boolean, default: 1, optional) (use command line)
# -profiling (boolean, default: 1, optional) (terminal print results)
# (prof results are written to file)
% prof str
prof str
input: str -auto {Ford F150} -kitchen spiffy!
----------------
>> 2.15 usec/sample str (samples 500000)
===============================================
Profiling results:
FS filename: profile.prof__90e2a0__.csv
Program: str -auto {Ford F150} -kitchen spiffy!
Samples: 500000
Medians: 20,269,330
Ratios: sv/fix: 13.45 pa/sv: 1.23
===============================================
</code></pre>
<p>In this example, median time for fixed args was 20nsec, writing default variables was 269nsec and command line arguments took 330nsec. Ratio of last two results was 1.23.</p>
<pre><code>% prof num
prof num
input: num -doors 8 -frac 0.874
----------------
>> 2.40 usec/sample num (samples 500000)
===============================================
Profiling results:
FS filename: profile.prof__90e2a0__.csv
Program: num -doors 8 -frac 0.874
Samples: 500000
Medians: 19,247,454
Ratios: sv/fix: 13.00 pa/sv: 1.84
===============================================
</code></pre>
<p>A procedure with numeric inputs shows very similar timing for fixed args and default vars. However, time to parse command line args was greater vs. string input. Reasons for this difference are discussed in the "Performance" section.</p>
<p>In "config.def" in unix and win (tcl8 and tcl9) directories, the Defaults list includes "profile 0". Therefore running <code>config -profile=1</code> generates a Makefile with "-DPROFILE". Then <code>make clean; make install</code> produces profile-enabled extension. Obviously, running <code>config</code> and remaining steps deletes profiling.</p>
<h1 id="testing-and-performance"><strong>Testing and Performance</strong></h1>
<p>Included in the "test" directory are tests that can be used to gain information about <em>nxproc</em> procedures. Profiling with "prof" was discussed above. The "oonxtest.tcl" file contains a "runtests" method that provides information about performance.</p>
<pre><code># "runtest" syntax:
# Timer create tmr0
# tmr0 runtests <type, function/effect> {default value}
# -ls <list of tests to run> {use tmrtm}
# -start <int >= 0, begin at index in ls> {0}
# -stop <int <= length of ls, stop at ndx> {ls length}
# -filenm <where to write results> {none/console output}
# -fmode <a == append, w == truncate+write> {a, append}
# -meminfo <boolean, exec 'memory info'> {off}
# -noshow <boolean, true->no console output> {off}
# -nocfg <boolean, true->don't use list config {off}
</code></pre>
<p>In general performance characteristics of <em>nxproc</em> procedures are good to excellent. Performance is affected by several factors.</p>
<p>First, <em>nxproc</em> procedures are not as performant as native Tcl <em>procs</em>. The basic reason for this is, as noted above, <em>nxproc</em> produces an "inner" command enclosed in a Tcl <em>proc</em>. In effect it's a <em>proc</em> call within a <em>proc</em> call. While unavoidably common in Tcl code it nonetheless has some, if usually modest, overhead.</p>
<!-- <div style="page-break-after: always"></div> -->
<p>In general, fixed args (with or without defaults) are faster than named args especially when there are several. As a rule, the greater the number of named args the longer it will take to accommodate all inputs. Likewise, longer command lines contribute to longer command runtime. These effects vary by type of input, length of lists to look through and related factors.</p>
<p>OTOH nxargs processing confers almost no performance penalty, whereas nxunknown can be slower. This is due to the fairly involved task of sorting unknown elements on the command line from expected input.</p>
<p>In any case, in the tmrtm suite most tests completed in under 2 microsec on a Windows laptop (11th gen processor, 16GB ram) with results varying on running under Windows 11 directly or in a WSL2 Linux terminal. No test required more than 2.5 microsec. Results also depend on versions of Tcl employed. There is considerable info available using a symbol-enabled Tcl. This is of course roughly 10 times slower compared to a "normally" compiled Tcl. In brief, <em>nxproc</em> was only 5-7% slower and without greater memory usage vs. standard versions.</p>
<p>More complex tests have to be judged by different standards. The test suite can evaluate creating a test website. This of course is orders of magnitude slower. A typical performance was ~400 microseconds/iter on regular Tcl and ~4000 microsec/iter on symbols-mem compiled Tcl. Performance in such applications is normally not crucial and is in practice very satisfactory for such purposes.</p>
<p>Where performance is important it's recommended to use standard proc/method calls. <em>nxproc</em> may suffice if fixed arg/nxargs use will work. Named arguments are an excellent approach to configuration/initialization where many input parameters would be expected. By its nature this use case is seldom time-critical, so application performance will not be affect adversely.</p>
</body>
</html>