<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE TIP SYSTEM "http://tcl.activestate.com/cgi-bin/tct/tip/tipxml.dtd">
<!-- Converted at Thu Feb 09 11:27:41 GMT 2012 -->
<!-- TIP AutoGenerator - written by Donal K. Fellows -->

<TIP number='77'>
<header><title>Support for Nested Paired Item Lists</title><author address="mailto:xian@planetoutpartners.com">Christian Williams</author><status type='project' state='withdrawn' tclversion="8.5" vote='prior'>$Revision: 1.3 $</status><history></history><created day='7' month='dec' year='2001' /><obsoleted tip='111'/></header>
<abstract>Tcl arrays can be transformed to and from lists using the <emph style="italic">array get</emph> and <emph style="italic">array set</emph> commands. This TIP proposes a new command for working directly these paired lists, and extending them to allow nesting in a manner analogous to <tipref type="text" tip="22"/>.</abstract>
<body><section title="Rationale">
<para>Tcl lists provide only ordinal access to their items; often it makes more sense to access items by pre-assigned descriptive names. This can be easily accomplished with Tcl arrays. Consider these alternatives:</para>
<verbatim><vline encoding='base64'>ICBzZXQgdXJsTGlzdCB7IGh0dHAgdGNsLmFjdGl2ZXN0YXRlLmNvbSA4MCAvaW5kZXguaHRtbCB9</vline><vline encoding='base64'></vline><vline encoding='base64'>ICBhcnJheSBzZXQgdXJsQXJyYXkgew==</vline><vline encoding='base64'>ICAgICAgIHByb3RvICAgaHR0cA==</vline><vline encoding='base64'>ICAgICAgIGhvc3QgICAgdGNsLmFjdGl2ZXN0YXRlLmNvbQ==</vline><vline encoding='base64'>ICAgICAgIHBvcnQgICAgODA=</vline><vline encoding='base64'>ICAgICAgIHVyaSAgICAgL2luZGV4Lmh0bWw=</vline><vline encoding='base64'>ICB9</vline></verbatim>
<para>Clearly the array approach promotes more readable code (<emph style="italic">$urlArray(host)</emph> versus <emph style="italic">[lindex $urlList 1]</emph>).</para>
<para>However, it&apos;s quite unwieldy and sometimes expensive to use arrays to access members of many sets of structured data, particularly when that data contains nested structures.</para>
<para>Consider this structured data:</para>
<verbatim><vline encoding='base64'>ICBzZXQgZGF0YSB7</vline><vline encoding='base64'>ICAgICAgIHRleHQgICAge2lnbm9yZWQtZGF0YX0=</vline><vline encoding='base64'>ICAgICAgIHZhbGlkLXN0eWxlcyB7</vline><vline encoding='base64'>ICAgICAgICAgICAgICAganVzdGlmaWNhdGlvbiB7bGVmdCBjZW50ZXJlZCByaWdodCBmdWxsfQ==</vline><vline encoding='base64'>ICAgICAgICAgICAgICAgZm9udCAgICAgICAgICB7Y291cmllciBoZWx2ZXRpY2EgdGltZXN9</vline><vline encoding='base64'>ICAgICAgIH0=</vline><vline encoding='base64'>ICB9</vline></verbatim>
<para>Extracting items from structures like this can be accomplished by multiple <emph style="italic">array set</emph> commands:</para>
<verbatim><vline encoding='base64'>ICBhcnJheSBzZXQgZGF0YUFycmF5ICRkYXRh</vline><vline encoding='base64'>ICBhcnJheSBzZXQgdmFsaWRTdHlsZXNBcnJheSAkZGF0YUFycmF5KHZhbGlkLXN0eWxlcyk=</vline><vline encoding='base64'>ICBwdXRzICJKdXN0aWZpY2F0aW9uOiAkdmFsaWRTdHlsZXNBcnJheShqdXN0aWZpY2F0aW9uKSI=</vline></verbatim>
<para>To modify an item in <emph style="italic">struct</emph>, we need some pretty ugly code:</para>
<verbatim><vline encoding='base64'>ICBhcnJheSBzZXQgZGF0YUFycmF5ICRzdHJ1Y3Q=</vline><vline encoding='base64'>ICBhcnJheSBzZXQgdmFsaWRTdHlsZXNBcnJheSAkZGF0YUFycmF5KHZhbGlkLXN0eWxlcyk=</vline><vline encoding='base64'>ICBzZXQgdmFsaWRTdHlsZXNBcnJheShqdXN0aWZpY2F0aW9uKSB7bGVmdH0=</vline><vline encoding='base64'>ICBzZXQgZGF0YUFycmF5KHZhbGlkLXN0eWxlcykgW2FycmF5IGdldCB2YWxpZFN0eWxlc0FycmF5XQ==</vline><vline encoding='base64'>ICBzZXQgZGF0YSBbYXJyYXkgZ2V0IGRhdGFBcnJheV0=</vline></verbatim>
<para>Clearly, all this setting and getting of arrays imposes a rather high overhead; many variables are created and moved around. Also, if this is occurring in a loop, then care must be taken to unset the <emph style="italic">dataArray</emph> and <emph style="italic">validStylesArray</emph> arrays first.</para>
<para>In contrast, a C programmer may expect that code to look more like this:</para>
<verbatim><vline encoding='base64'>ICBkYXRhLT52YWxpZC1zdHlsZXMtPmp1c3RpZmljYXRpb24gPSAnbGVmdCc7</vline></verbatim>
<para>Extending Tcl with a command supporting nested, paired item lists would permit very efficient and readable handling of these useful data structures.</para>
</section>
<section title="Specification">
<para>Under this proposal, a new command named <emph style="italic">pair</emph> (referring to the pairs of name/value list items it works with) would be added to the Tcl core.</para>
<para>A well-formed paired list is defined as a well-formed Tcl list whose length is evenly divisible by two. In each pair of list items, the first item gives the name of the pair, and the second gives the value. Paired lists may be nested by placing a valid paired list in the second (value) item of any pair. Note that the pairs are not grouped together into a two-item list as in TclX&apos;s keyed lists. Tcl&apos;s <emph style="italic">array get</emph> command returns a well-formed paired list.</para>
<para>The syntax for the new <emph style="italic">pair</emph> command would be:</para>
<verbatim><vline encoding='base64'>ICBwYWlyIG9wdGlvbiB2YXJpYWJsZSBub2RlID9uZXdWYWx1ZT8=</vline></verbatim>
<para>Valid values for the <emph style="italic">options</emph> argument include <emph style="italic">get</emph>, <emph style="italic">set</emph>, <emph style="italic">unset</emph>, <emph style="italic">exists</emph>, and <emph style="italic">append</emph>. These subcommands are equivalent to the existing Tcl commands of the same names.</para>
<para>The <emph style="italic">variable</emph> argument is the name of a Tcl variable; it is always referred to by name, not by its value (that is, no <emph style="italic">$</emph>). Generally, the variable would contain a well-formed, and optionally nested, paired list.</para>
<para>The <emph style="italic">node</emph> argument is a well-formed Tcl list of zero or more items specifying the route to the item we&apos;re interested in.</para>
<para>For example:</para>
<verbatim><vline encoding='base64'>ICBzZXQgZGF0YSB7</vline><vline encoding='base64'>ICAgICAgIHRleHQgICAge2lnbm9yZWQtZGF0YX0=</vline><vline encoding='base64'>ICAgICAgIHZhbGlkLXN0eWxlcyB7</vline><vline encoding='base64'>ICAgICAgICAgICAgICAganVzdGlmaWNhdGlvbiB7bGVmdCBjZW50ZXJlZCByaWdodCBmdWxsfQ==</vline><vline encoding='base64'>ICAgICAgICAgICAgICAgZm9udCAgICAgICAgICB7Y291cmllciBoZWx2ZXRpY2EgdGltZXN9</vline><vline encoding='base64'>ICAgICAgIH0=</vline><vline encoding='base64'>ICB9</vline><vline encoding='base64'></vline><vline encoding='base64'>ICBwdXRzICJKdXN0aWZpY2F0aW9uOiBbcGFpciBnZXQgZGF0YSB7dmFsaWQtc3R5bGVzIGp1c3RpZmljYXRpb259XSI=</vline></verbatim>
<para>displays &quot;Justification: left centered right full&quot;.</para>
<para>If the <emph style="italic">data</emph> argument contains zero items, then the &quot;root&quot; node of the variable is targeted -- that is, the entire variable:</para>
<verbatim><vline encoding='base64'>ICBwYWlyIHNldCBub2RlIHt9IG5ldy12YWx1ZQ==</vline><vline encoding='base64'>ICBwdXRzICRub2Rl</vline></verbatim>
<para>displays &quot;new-value&quot;.</para>
<para>If a non-existent node is targeted using the <emph style="italic">get</emph> or <emph style="italic">unset</emph> options, an error is returned:</para>
<verbatim><vline encoding='base64'>ICB1bnNldCB4</vline><vline encoding='base64'>ICBwYWlyIGdldCB4IHtmaXJzdCBzZWNvbmQgdGhpcmR9</vline><vline encoding='base64'>ICAtPiBubyBzdWNoIHZhbHVl</vline></verbatim>
<para>If a non-existent node is targeted using the <emph style="italic">set</emph> or <emph style="italic">append</emph> options, the node, and any parent nodes, are created.</para>
<verbatim><vline encoding='base64'>ICB1bnNldCB4</vline><vline encoding='base64'>ICBwYWlyIHNldCB4IHtmaXJzdCBzZWNvbmQgdGhpcmR9IHZhbHVl</vline><vline encoding='base64'>ICBwdXRzICR4</vline></verbatim>
<para>displays &quot;first {second {third value}}&quot;</para>
<para>The <emph style="italic">exists</emph> option mimics Tcl&apos;s <emph style="italic">info exists</emph> command:</para>
<verbatim><vline encoding='base64'>ICBzZXQgeCB7bmFtZSB2YWx1ZX0=</vline><vline encoding='base64'>ICBwYWlyIGV4aXN0cyB4IG5hbWU=</vline><vline encoding='base64'>ICAtPiAx</vline><vline encoding='base64'>ICBwYWlyIGV4aXN0cyB4IG5hbWUy</vline><vline encoding='base64'>ICAtPiAw</vline></verbatim>
<para>The <emph style="italic">set</emph> and <emph style="italic">append</emph> options return the value of the node that has just been set, not the value of the variable. This would seem to be more in keeping with the intent of Tcl&apos;s <emph style="italic">set</emph> and <emph style="italic">append</emph> commands&apos; return values than duplicating the exact behaviour:</para>
<verbatim><vline encoding='base64'>ICBwdXRzIFtwYWlyIHNldCB4IHtmaXJzdCBzZWNvbmQgdGhpcmR9IHZhbHVlXQ==</vline></verbatim>
<para>displays &quot;value&quot;.</para>
<para>An error is returned if a variable is passed to the <emph style="italic">pair</emph> command which doesn&apos;t contain a well-formed paired Tcl list at any point on the way to the node specified by the <emph style="italic">node</emph> argument:</para>
<verbatim><vline encoding='base64'>ICBzZXQgeCB7bmFtZSB2YWx1ZSB0aGlyZGFyZ30=</vline><vline encoding='base64'>ICBwYWlyIGdldCB4IG5hbWU=</vline><vline encoding='base64'>ICAtPiBsaXN0IG11c3QgaGF2ZSBhbiBldmVuIG51bWJlciBvZiBlbGVtZW50cw==</vline></verbatim>
<para>If there are traces registered on the variable passed to the <emph style="italic">pair</emph> command, they are triggered in the same manner as Tcl&apos;s <emph style="italic">set</emph> and <emph style="italic">append</emph> commands. Note that the <emph style="italic">append</emph> option triggers only write triggers, not read triggers.</para>
<para>Note that the <emph style="italic">set</emph> and <emph style="italic">append</emph> options both return the value of the node specified, and the <emph style="italic">newValue</emph> argument is optional in both cases, making the <emph style="italic">get</emph> option redundant. The <emph style="italic">get</emph> command is included to improve readability.</para>
<para>If the variable passed to <emph style="italic">pair</emph> doesn&apos;t exist, it will be created if the option is &apos;set&apos; or <emph style="italic">append</emph>; the <emph style="italic">exists</emph> option will always return a <emph style="italic">0</emph>; the <emph style="italic">get</emph> option will return an error.</para>
<para>If a paired list contains multiple pairs with identical names, the pair occurring later in the list is targeted. This is specified to mimic the behaviour of <emph style="italic">array set</emph>:</para>
<verbatim><vline encoding='base64'>ICBzZXQgeCAibmFtZSB2YWx1ZTEgbmFtZSB2YWx1ZTIi</vline><vline encoding='base64'>ICBwYWlyIGdldCB4IG5hbWU=</vline><vline encoding='base64'>ICAtPiB2YWx1ZTI=</vline><vline encoding='base64'></vline><vline encoding='base64'>ICBhcnJheSBzZXQgYXJyWCAkeA==</vline><vline encoding='base64'>ICBzZXQgYXJyWChuYW1lKQ==</vline><vline encoding='base64'>ICAtPiB2YWx1ZTI=</vline></verbatim>
</section>
<section title="Reference Implementation">
<para><url ref="http://sf.net/tracker/?func=detail&amp;aid=491070&amp;group_id=10894&amp;atid=310894"/></para>
<para>There should be a public C API for working with nested paired lists. The supplied reference code currently does not provide this.</para>
</section>
<section title="Notes">
<para>It would be nice to mimic Tcl 8.4&apos;s new <emph style="italic">unset -nocomplain</emph> behaviour.</para>
</section>
<section title="Side Effects">
<para>Whether the result of the pair operation is successful, the underlying Tcl_Obj that represents the list argument may have its internal representation invalidated or changed to that of a list.</para>
</section>
<section title="Copyright">
<para>This document has been placed in the public domain.</para>
</section>
</body></TIP>

