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

<TIP number='314'>
<header><title>Ensembles with Parameters</title><author address="mailto:Lars.Hellstrom@residenset.net">Lars Hellström</author><status type='project' state='final' tclversion="8.6" vote='after'>$Revision: 1.5 $</status><history></history><created day='26' month='feb' year='2008' /></header>
<abstract>This TIP proposes that <emph style="bold">namespace ensemble</emph> commands are generalised so that they may have arguments before the subcommand name.</abstract>
<body><section title="Rationale">
<para>The introduction of <emph style="bold">{*}</emph> for argument expansion has made it much more convenient to use command prefixes for callbacks. One particular idiom that command prefixes provide for is &quot;ClientData&quot; arguments, i.e., the same command is used for several different callbacks, as exactly what it does or acts on is controlled by the extra argument(s). Of course, both command prefixes and the &quot;ClientData&quot; idiom are already the rule for callbacks from the core, but <emph style="bold">{*}</emph> will most likely make them more common also for callbacks from Tcl code.</para>
<para>A disadvantage of this idiom is however that it currently cannot be used if the base command of a command prefix is to be an ensemble, as the subcommand name in an ensemble must follow immediately after the base command name. Callbacks from the core which take a subcommand are rare - the only obvious example is the reflected channel callback command - but in higher level code such callbacks are fairly common. Using namespace ensembles for implementing such callbacks makes the code much more modular than using a procedure would. Hence it is desirable to remove the restriction that the subcommand name of a namespace ensemble must appear as the first argument, and instead allow there to be some number of &quot;parameter&quot; arguments between the base command name and the subcommand name.</para>
<para>One application of parameter arguments is to use namespace ensembles as a white-box OO system, where the parameters hold the state of the object. More explicitly, each object instance in such a system would be a command prefix consisting of (i) one ensemble command that handles the method dispatch and (ii) the necessary number of parameter arguments, whose values make up the state of the object. Being values, such objects are necessarily immutable; it is however possible to define methods which return a mutated form of the object. For light-weight objects, this system has the advantage that instances do not have to be destroyed explicitly, but of course that also means that they cannot own any resources that require explicit destruction.</para>
<para>Some may argue that ensemble parameters are not necessary because any client data can be embedded into the prefixes of the <emph style="bold">-map</emph> dictionary of the ensemble. This is however only true to the extent that multiword command prefixes themselves are unnecessary; it is similarly possible to embed extra arguments into an <emph style="bold">interp alias</emph>. Both of these &quot;solutions&quot; have the disadvantage that they create an auxiliary command which one must explicitly dispose of or leak memory, whereas all memory used by a command prefix is automatically released when the last reference to it goes away.</para>
</section>
<section title="Specification">
<para>A new ensemble option <emph style="bold">-parameters</emph> is introduced, which takes a list of parameter names as value and defaults to the empty list. Two C functions for setting and getting the value of this option are added to the public stubs table:</para>
<quote>int <emph style="bold">Tcl_SetEnsembleParameterList</emph>(Tcl_Interp *<emph style="italic">interp</emph>, Tcl_Command <emph style="italic">token</emph>, Tcl_Obj *<emph style="italic">paramList</emph>)</quote>
<quote>int <emph style="bold">Tcl_GetEnsembleParameterList</emph>(Tcl_Interp *<emph style="italic">interp</emph>, Tcl_Command <emph style="italic">token</emph>, Tcl_Obj **<emph style="italic">paramListPtr</emph>)</quote>
<para>(This is the same pattern as for the other ensemble options, e.g. for the <emph style="bold">-subcommands</emph> option&apos;s implementation.)</para>
<para>The general structure of a namespace ensemble command call will have the form:</para>
<quote><emph style="italic">baseCmd</emph> {*}<emph style="italic">parameterArgs</emph> <emph style="italic">subCmd</emph> {*}<emph style="italic">otherArgs</emph></quote>
<para>where the number of arguments between the base command and the subcommand is exactly the same as the number of elements in the value of the <emph style="bold">-parameters</emph> option. It is an error to call the <emph style="italic">baseCmd</emph> with fewer arguments than the number of parameters plus one. If <emph style="italic">cmdPrefix</emph> is the command prefix to which the ensemble <emph style="italic">baseCmd</emph> maps the <emph style="italic">subCmd</emph>, then the above call gets translated into</para>
<quote>{*}<emph style="italic">cmdPrefix</emph> {*}<emph style="italic">parameterArgs</emph> {*}<emph style="italic">otherArgs</emph></quote>
</section>
<section title="Examples">
<para>An ensemble for arithmetic in integer-modulo-<emph style="italic">n</emph> rings can be implemented as follows:</para>
<verbatim><vline encoding='base64'>IG5hbWVzcGFjZSBldmFsIGludG1vZCB7</vline><vline encoding='base64'>ICAgICBwcm9jICsge24gYXJnc30ge2V4cHIge1s6OnRjbDo6bWF0aG9wOjorIHsqfSRhcmdzXSAlICRufX0=</vline><vline encoding='base64'>ICAgICBwcm9jIC0ge24gYXJnc30ge2V4cHIge1s6OnRjbDo6bWF0aG9wOjotIHsqfSRhcmdzXSAlICRufX0=</vline><vline encoding='base64'>ICAgICBwcm9jICoge24gYXJnc30ge2V4cHIge1s6OnRjbDo6bWF0aG9wOjoqIHsqfSRhcmdzXSAlICRufX0=</vline><vline encoding='base64'>ICAgICBwcm9jIC8ge24gYSBifSB7</vline><vline encoding='base64'>ICAgICAgICAgc2V0IGMgJG4=</vline><vline encoding='base64'>ICAgICAgICAgc2V0IHIgMA==</vline><vline encoding='base64'>ICAgICAgICAgc2V0IHMgMQ==</vline><vline encoding='base64'>ICAgICAgICAgd2hpbGUgeyRifSB7</vline><vline encoding='base64'>ICAgICAgICAgICAgIHNldCBxIFtleHByIHskYyAvICRifV0=</vline><vline encoding='base64'>ICAgICAgICAgICAgIHNldCBiIFtleHByIHskYyAtICRxKltzZXQgYyAkYl19XQ==</vline><vline encoding='base64'>ICAgICAgICAgICAgIHNldCBzIFtleHByIHskciAtICRxKltzZXQgciAkc119XQ==</vline><vline encoding='base64'>ICAgICAgICAgfQ==</vline><vline encoding='base64'>ICAgICAgICAgaWYgeyRhICUgJGMgPT0gMH0gdGhlbiB7</vline><vline encoding='base64'>ICAgICAgICAgICAgIHJldHVybiBbZXhwciB7JHIgKiAkYSAvICRjICUgJG59XQ==</vline><vline encoding='base64'>ICAgICAgICAgfSBlbHNlIHs=</vline><vline encoding='base64'>ICAgICAgICAgICAgIHJldHVybiAtY29kZSBlcnJvciAiTm8gc3VjaCBxdW90aWVudCI=</vline><vline encoding='base64'>ICAgICAgICAgfQ==</vline><vline encoding='base64'>ICAgICB9</vline><vline encoding='base64'>ICAgICBwcm9jIDAge259IHtyZXR1cm4gMH0=</vline><vline encoding='base64'>ICAgICBwcm9jIDEge259IHtyZXR1cm4gMX0=</vline><vline encoding='base64'>ICAgICBuYW1lc3BhY2UgZW5zZW1ibGUgY3JlYXRlIC1wYXJhbWV0ZXJzIG4gLXN1YmNvbW1hbmRzIHsrIC0gKiAvIDAgMX0=</vline><vline encoding='base64'>ICAgICAjIFRoYXQgW25hbWVzcGFjZSBleHBvcnRdIHRha2VzIHBhdHRlcm5zIGFzIGFyZ3VtZW50cyBzdGFydHM=</vline><vline encoding='base64'>ICAgICAjIGZlZWxpbmcgc29tZXdoYXQgY29ybnkgd2hlbiAqIGlzIGEgY29tbW9uIGNvbW1hbmQgbmFtZXMu</vline><vline encoding='base64'>IH0=</vline></verbatim>
<para>Some example results:</para>
<verbatim><vline encoding='base64'>ICUgaW50bW9kIDcgKyA0IDQ=</vline><vline encoding='base64'>IDE=</vline><vline encoding='base64'>ICUgaW50bW9kIDcgLSAx</vline><vline encoding='base64'>IDY=</vline><vline encoding='base64'>ICUgaW50bW9kIDcgKiAzIDU=</vline><vline encoding='base64'>IDE=</vline><vline encoding='base64'>ICUgaW50bW9kIDcgLyAzIDI=</vline><vline encoding='base64'>IDU=</vline><vline encoding='base64'>ICUgaW50bW9kIDMyMDAzIC8gMyAy</vline><vline encoding='base64'>IDE2MDAz</vline><vline encoding='base64'>ICUgaW50bW9kIDMyNzY4IC8gMyAy</vline><vline encoding='base64'>IE5vIHN1Y2ggcXVvdGllbnQ=</vline><vline encoding='base64'>ICUgaW50bW9k</vline><vline encoding='base64'>IHdyb25nICMgYXJnczogc2hvdWxkIGJlICJpbnRtb2QgbiBzdWJjb21tYW5kID9hcmd1bWVudCAuLi4/Ig==</vline></verbatim>
<para>An ensemble for matrix arithmetic over some ring can be implemented as follows:</para>
<verbatim><vline encoding='base64'>IG5hbWVzcGFjZSBldmFsIG1hdHJpeCB7</vline><vline encoding='base64'>ICAgICBwcm9jICsge3JpbmcgQSBCfSB7</vline><vline encoding='base64'>ICAgICAgICAgaWYge1tsbGVuZ3RoICRBXSAhPSBbbGxlbmd0aCAkQl0gfHw=</vline><vline encoding='base64'>ICAgICAgICAgICAgIFtsbGVuZ3RoIFtsaW5kZXggJEEgMF1dICE9IFtsbGVuZ3RoIFtsaW5kZXggJEIgMF1dfSB0aGVuIHs=</vline><vline encoding='base64'>ICAgICAgICAgICAgIHJldHVybiAtY29kZSBlcnJvciAtZXJyb3Jjb2RlIHtBUklUSCBET01BSU59</vline><vline encoding='base64'>ICAgICAgICAgICAgICAgIk1hdHJpeCBzaGFwZXMgZG8gbm90IG1hdGNoIg==</vline><vline encoding='base64'>ICAgICAgICAgfQ==</vline><vline encoding='base64'>ICAgICAgICAgc2V0IHJlcyB7fQ==</vline><vline encoding='base64'>ICAgICAgICAgZm9yZWFjaCBhX3JvdyAkQSBiX3JvdyAkQiB7</vline><vline encoding='base64'>ICAgICAgICAgICAgIHNldCByX3JvdyB7fQ==</vline><vline encoding='base64'>ICAgICAgICAgICAgIGZvcmVhY2ggYSAkYV9yb3cgYiAkYl9yb3cgew==</vline><vline encoding='base64'>ICAgICAgICAgICAgICAgICBsYXBwZW5kIHJfcm93IFt7Kn0kcmluZyArICRhICRiXQ==</vline><vline encoding='base64'>ICAgICAgICAgICAgIH0=</vline><vline encoding='base64'>ICAgICAgICAgICAgIGxhcHBlbmQgcmVzICRyX3Jvdw==</vline><vline encoding='base64'>ICAgICAgICAgfQ==</vline><vline encoding='base64'>ICAgICAgICAgcmV0dXJuICRyZXM=</vline><vline encoding='base64'>ICAgICB9</vline><vline encoding='base64'>ICAgICBwcm9jIC0ge3JpbmcgQSBCfSB7</vline><vline encoding='base64'>ICAgICAgICAgaWYge1tsbGVuZ3RoICRBXSAhPSBbbGxlbmd0aCAkQl0gfHw=</vline><vline encoding='base64'>ICAgICAgICAgICAgIFtsbGVuZ3RoIFtsaW5kZXggJEEgMF1dICE9IFtsbGVuZ3RoIFtsaW5kZXggJEIgMF1dfSB0aGVuIHs=</vline><vline encoding='base64'>ICAgICAgICAgICAgIHJldHVybiAtY29kZSBlcnJvciAtZXJyb3Jjb2RlIHtBUklUSCBET01BSU59</vline><vline encoding='base64'>ICAgICAgICAgICAgICAgIk1hdHJpeCBzaGFwZXMgZG8gbm90IG1hdGNoIg==</vline><vline encoding='base64'>ICAgICAgICAgfQ==</vline><vline encoding='base64'>ICAgICAgICAgc2V0IHJlcyB7fQ==</vline><vline encoding='base64'>ICAgICAgICAgZm9yZWFjaCBhX3JvdyAkQSBiX3JvdyAkQiB7</vline><vline encoding='base64'>ICAgICAgICAgICAgIHNldCByX3JvdyB7fQ==</vline><vline encoding='base64'>ICAgICAgICAgICAgIGZvcmVhY2ggYSAkYV9yb3cgYiAkYl9yb3cgew==</vline><vline encoding='base64'>ICAgICAgICAgICAgICAgICBsYXBwZW5kIHJfcm93IFt7Kn0kcmluZyAtICRhICRiXQ==</vline><vline encoding='base64'>ICAgICAgICAgICAgIH0=</vline><vline encoding='base64'>ICAgICAgICAgICAgIGxhcHBlbmQgcmVzICRyX3Jvdw==</vline><vline encoding='base64'>ICAgICAgICAgfQ==</vline><vline encoding='base64'>ICAgICAgICAgcmV0dXJuICRyZXM=</vline><vline encoding='base64'>ICAgICB9</vline><vline encoding='base64'>ICAgICBwcm9jICoge3JpbmcgQSBCfSB7</vline><vline encoding='base64'>ICAgICAgICAgaWYge1tsbGVuZ3RoIFtsaW5kZXggJEEgMF1dICE9IFtsbGVuZ3RoICRCXX0gdGhlbiB7</vline><vline encoding='base64'>ICAgICAgICAgICAgIHJldHVybiAtY29kZSBlcnJvciAtZXJyb3Jjb2RlIHtBUklUSCBET01BSU59</vline><vline encoding='base64'>ICAgICAgICAgICAgICAgIk1hdHJpeCBzaGFwZXMgZG8gbm90IG1hdGNoIg==</vline><vline encoding='base64'>ICAgICAgICAgfQ==</vline><vline encoding='base64'>ICAgICAgICAgc2V0IHJlcyB7fQ==</vline><vline encoding='base64'>ICAgICAgICAgZm9yZWFjaCBhX3JvdyAkQSB7</vline><vline encoding='base64'>ICAgICAgICAgICAgIHNldCByX3JvdyB7fQ==</vline><vline encoding='base64'>ICAgICAgICAgICAgIGZvcmVhY2ggYSAkYV9yb3cgYl9yb3cgJEIgew==</vline><vline encoding='base64'>ICAgICAgICAgICAgICAgICBzZXQgciBbeyp9JHJpbmcgMF0=</vline><vline encoding='base64'>ICAgICAgICAgICAgICAgICBmb3JlYWNoIGIgJGJfcm93IHs=</vline><vline encoding='base64'>ICAgICAgICAgICAgICAgICAgICAgc2V0IHIgW3sqfSRyaW5nICsgJHIgW3sqfSRyaW5nICogJGEgJGJdXQ==</vline><vline encoding='base64'>ICAgICAgICAgICAgICAgICB9</vline><vline encoding='base64'>ICAgICAgICAgICAgICAgICBsYXBwZW5kIHJfcm93ICRy</vline><vline encoding='base64'>ICAgICAgICAgICAgIH0=</vline><vline encoding='base64'>ICAgICAgICAgICAgIGxhcHBlbmQgcmVzICRyX3Jvdw==</vline><vline encoding='base64'>ICAgICAgICAgfQ==</vline><vline encoding='base64'>ICAgICAgICAgcmV0dXJuICRyZXM=</vline><vline encoding='base64'>ICAgICB9</vline><vline encoding='base64'>ICAgICAjIC4uLg==</vline><vline encoding='base64'>ICAgICBuYW1lc3BhY2UgZXhwb3J0ICo=</vline><vline encoding='base64'>ICAgICBuYW1lc3BhY2UgZW5zZW1ibGUgY3JlYXRlIC1wYXJhbWV0ZXJzIHJpbmdDbWRQcmVmaXg=</vline><vline encoding='base64'>IH0=</vline></verbatim>
<para>Some more example results:</para>
<verbatim><vline encoding='base64'>ICUgc2V0IEEge3sxIDJ9IHszIDR9fQ==</vline><vline encoding='base64'>ICUgbWF0cml4IHtpbnRtb2QgN30gKyAkQSAkQQ==</vline><vline encoding='base64'>IHsyIDR9IHs2IDF9</vline><vline encoding='base64'>ICUgc2V0IEIge3swIDJ9IHsxIDN9fQ==</vline><vline encoding='base64'>ICUgbWF0cml4IHtpbnRtb2QgMTAwfSAqICRBICRC</vline><vline encoding='base64'>IHsyIDh9IHs2IDE2fQ==</vline><vline encoding='base64'>ICUgbWF0cml4IHtpbnRtb2QgNX0gKiAkQSAkQg==</vline><vline encoding='base64'>IHsyIDN9IHsxIDF9</vline><vline encoding='base64'>ICUgbWF0cml4IHtpbnRtb2QgNX0gLSAkQSAkQg==</vline><vline encoding='base64'>IHsxIDB9IHsyIDF9</vline><vline encoding='base64'>ICUgbWF0cml4</vline><vline encoding='base64'>IHdyb25nICMgYXJnczogc2hvdWxkIGJlICJtYXRyaXggcmluZ0NtZFByZWZpeCBzdWJjb21tYW5kID9hcmd1bWVudCAuLi4/Ig==</vline></verbatim>
<para>In the same way, one can define a <emph style="bold">polynomial</emph> ensemble for arithmetic with polynomials over some ring. Then one can immediately start doing calculations with e.g. matrices whose coefficients are polynomials over integers modulo 2, simply by using the command prefix</para>
<verbatim><vline encoding='base64'>IG1hdHJpeCB7cG9seW5vbWlhbCB7aW50bW9kIDJ9fQ==</vline></verbatim>
<para>Composing constructions this way is a surprisingly quick way of implementing rather complex mathematical structures!</para>
<para>A trivial mutable object class can be implemented as follows:</para>
<verbatim><vline encoding='base64'>IG5hbWVzcGFjZSBldmFsIG11dGFibGVfbnMgew==</vline><vline encoding='base64'>ICAgICBwcm9jIGdldCB7dmFsdWV9IHtyZXR1cm4gJHZhbHVlfQ==</vline><vline encoding='base64'>ICAgICBwcm9jIHNldCB7dmFsdWUgbmV3dmFsdWV9IHtsaXN0IFtuYW1lc3BhY2UgY3VycmVudF0gJG5ld3ZhbHVlfQ==</vline><vline encoding='base64'>ICAgICBuYW1lc3BhY2UgZXhwb3J0IGdldCBzZXQ=</vline><vline encoding='base64'>ICAgICBuYW1lc3BhY2UgZW5zZW1ibGUgY3JlYXRlIC1wYXJhbWV0ZXJzIHZhbHVl</vline><vline encoding='base64'>IH0=</vline><vline encoding='base64'>IHByb2MgbXV0YWJsZSB7aW5pdHZhbH0gew==</vline><vline encoding='base64'>ICAgICBsaXN0IFtuYW1lc3BhY2Ugd2hpY2ggLWNvbW1hbmQgbXV0YWJsZV9uc10gJGluaXR2YWw=</vline><vline encoding='base64'>IH0=</vline></verbatim>
<para>Some example results:</para>
<verbatim><vline encoding='base64'>ICUgc2V0IGEgW211dGFibGUgMF0=</vline><vline encoding='base64'>IDo6bXV0YWJsZV9ucyAw</vline><vline encoding='base64'>ICUgeyp9JGEgZ2V0</vline><vline encoding='base64'>IDA=</vline><vline encoding='base64'>ICUgeyp9JGEgZm9v</vline><vline encoding='base64'>IHVua25vd24gb3IgYW1iaWd1b3VzIHN1YmNvbW1hbmQgImZvbyI6IG11c3QgYmUgZ2V0LCBvciBzZXQ=</vline><vline encoding='base64'>ICUgc2V0IGIgW3sqfSRhIHNldCAzXSA7ICMgQ3JlYXRlcyBhIG1vZGlmaWVkIGNvcHk=</vline><vline encoding='base64'>IDo6bXV0YWJsZV9ucyAz</vline><vline encoding='base64'>ICUgeyp9JGIgZ2V0</vline><vline encoding='base64'>IDM=</vline><vline encoding='base64'>ICUgeyp9JGEgZ2V0</vline><vline encoding='base64'>IDA=</vline></verbatim>
</section>
<section title="Rejected Alternatives">
<para>Most of the time, only the number of parameters is relevant; their names are merely used when throwing a &quot;wrong # args&quot; error. Hence an alternative would be to have taken that number as the value of the <emph style="bold">-parameters</emph> option, but requesting a list of names encourages the programmer to provide more information available for introspection and should help to produce better error messages.</para>
<para>An alternative principle for forming the mapped-to command could be that the parameters should remain in the same position in the command. This would mean that rather than mapping</para>
<quote><emph style="italic">baseCmd</emph> {*}<emph style="italic">parameterArgs</emph> <emph style="italic">subCmd</emph> {*}<emph style="italic">otherArgs</emph></quote>
<para>to</para>
<quote>{*}<emph style="italic">cmdPrefix</emph> {*}<emph style="italic">parameterArgs</emph> {*}<emph style="italic">otherArgs</emph></quote>
<para>one would map it to</para>
<quote>[<emph style="bold">lindex</emph> <emph style="italic">cmdPrefix</emph> 0] {*}<emph style="italic">parameterArgs</emph> {*}[<emph style="bold">lrange</emph> <emph style="italic">cmdPrefix</emph> 1 end] {*}<emph style="italic">otherArgs</emph></quote>
<para>but this is slightly more complicated to do, and it seems less useful. For example, this would prevent using an <emph style="bold">apply</emph> <emph style="italic">lambda</emph> form of <emph style="italic">cmdPrefix</emph> in an ensemble with parameters.</para>
</section>
<section title="Future Extensions">
<para>In analogy with the <emph style="bold">-unknown</emph> handler for an ensemble, it might be useful to have a handler for ensembles being called with <emph style="italic">too few</emph> arguments; it is not uncommon for ensemble-like commands that one in certain cases can omit the subcommand name. Possibly this functionality could even be integrated into the <emph style="bold">-unknown</emph> handler. There is however nothing in that which is directly related to the issue of ensembles having parameters, other than that parameters make it possible to call an ensemble command with way too few arguments instead of just one too few.</para>
</section>
<section title="Reference Implementation">
<para>A reference implementation is available as SF Tcl patch #1901783. [<url ref="https://sourceforge.net/support/tracker.php?aid=1901783"/>]</para>
<subsection title="Notes">
<para>One detail in this implementation which might require further consideration because it results in script-level-visible behaviour is the matter of how the list of parameter names is turned into error messages. Currently that is done by (effectively) <emph style="bold">join</emph>ing the list elements, but a possible alternative is to use the string representation of the list. Joining seems to give better control to the user of what gets put in the message, but the results are probably equivalent for all alphanumeric choices of parameter names.</para>
<para>Deep down, this touches upon the matter of how the user may distinguish actual argument values from formal argument names in syntax error messages. As far as I can tell, there currently isn&apos;t a way of doing that, but perhaps there should be. In want of clear rules for this, the reference implementation doesn&apos;t seem to fare any worse than what is already in the core.</para>
</subsection>
</section>
<section title="Copyright">
<para>This document has been placed in the public domain.</para>
</section>
</body></TIP>
