\documentclass[]{article}
\usepackage{amsmath,graphicx,supertabular,hyperref,tabularx,ifthen}
\title{TIP \#77: Support for Nested Paired Item Lists}
\date{December 07, 2001}
\author{Christian Williams}
\urlstyle{sf}
\setlength{\parskip}{1ex}
\setlength{\parindent}{0pt}
\def\tipversion$#1${\texttt{\$#1\$}}
\def\tiplangle#1{\ensuremath{<}}
\def\tiprangle#1{\ensuremath{>}}
\def\tipbar#1{\ensuremath{|}}
\def\tipmail#1#2{\(\langle\){\small\expandafter\url{#1@#2}}\(\rangle\)}
\ifx\pdfoutput\undefined
\newcommand{\tipimage}[2]{\typeout{Make sure you download #1.eps}\ifthenelse{\lengthtest{0.8\textwidth>#2}\and\lengthtest{0pt<#2}}{\includegraphics{#1.eps}}{\includegraphics[width=0.8\textwidth]{#1.eps}}}
\newcommand{\tipxref}[1]{}
\newcommand{\tipxrefend}{}
\else
\newcommand{\tipimage}[2]{\typeout{Make sure you create #1.pdf}\ifthenelse{\lengthtest{0.8\textwidth>#2}\and\lengthtest{0pt<#2}}{\includegraphics{#1.pdf}}{\includegraphics[width=0.8\textwidth]{#1.pdf}}}
\pdfcatalog{/PageMode /UseOutlines}
\newcommand{\tipxref}[1]{\pdfannotlink attr {/C [0.5 0.5 1.0] /Border [0 0 1]} goto name {#1}}
\newcommand{\tipxrefend}{\pdfendlink}
\fi
\newenvironment{tipabstract}{\begin{abstract}}{\end{abstract}}
\begin{document}\maketitle
\begin{center}\begin{tabularx}{\linewidth}{|r@{: }X|}\hline
\textbf{TIP \#77}&\textbf{Support for Nested Paired Item Lists}\\\hline
Author&

Christian Williams \tipmail{xian}{planetoutpartners.com}
\\
Created&Friday, \(\text{7}^{\text{th}}\) December 2001\\
Type&Project\\
Tcl Version&\(8.5\)\\
State&Withdrawn\\
Vote&Pending\\
Version&\tipversion$Revision: 1.3 $\\
Obsoleted By&111\\
Post History&\\
\hline\end{tabularx}\end{center}
\thispagestyle{empty}\pagestyle{empty}
\begin{tipabstract}

Tcl arrays can be transformed to and from lists using the \textit{array get} and \textit{array set} commands. This TIP proposes a new command for working directly these paired lists, and extending them to allow nesting in a manner analogous to \cite{tip22}.
\end{tipabstract}
\tableofcontents\setcounter{page}{0}\clearpage\pagestyle{plain}

\section{Rationale}

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:
\begingroup\small\begin{verbatim}
  set urlList { http tcl.activestate.com 80 /index.html }

  array set urlArray {
       proto   http
       host    tcl.activestate.com
       port    80
       uri     /index.html
  }
\end{verbatim}
\endgroup

Clearly the array approach promotes more readable code (\textit{\$urlArray(host)} versus \textit{[lindex \$urlList 1]}).

However, it'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.

Consider this structured data:
\begingroup\small\begin{verbatim}
  set data {
       text    {ignored-data}
       valid-styles {
               justification {left centered right full}
               font          {courier helvetica times}
       }
  }
\end{verbatim}
\endgroup

Extracting items from structures like this can be accomplished by multiple \textit{array set} commands:
\begingroup\small\begin{verbatim}
  array set dataArray $data
  array set validStylesArray $dataArray(valid-styles)
  puts "Justification: $validStylesArray(justification)"
\end{verbatim}
\endgroup

To modify an item in \textit{struct}, we need some pretty ugly code:
\begingroup\small\begin{verbatim}
  array set dataArray $struct
  array set validStylesArray $dataArray(valid-styles)
  set validStylesArray(justification) {left}
  set dataArray(valid-styles) [array get validStylesArray]
  set data [array get dataArray]
\end{verbatim}
\endgroup

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 \textit{dataArray} and \textit{validStylesArray} arrays first.

In contrast, a C programmer may expect that code to look more like this:
\begingroup\small\begin{verbatim}
  data->valid-styles->justification = 'left';
\end{verbatim}
\endgroup

Extending Tcl with a command supporting nested, paired item lists would permit very efficient and readable handling of these useful data structures.

\section{Specification}

Under this proposal, a new command named \textit{pair} (referring to the pairs of name/value list items it works with) would be added to the Tcl core.

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's keyed lists. Tcl's \textit{array get} command returns a well-formed paired list.

The syntax for the new \textit{pair} command would be:
\begingroup\small\begin{verbatim}
  pair option variable node ?newValue?
\end{verbatim}
\endgroup

Valid values for the \textit{options} argument include \textit{get}, \textit{set}, \textit{unset}, \textit{exists}, and \textit{append}. These subcommands are equivalent to the existing Tcl commands of the same names.

The \textit{variable} argument is the name of a Tcl variable; it is always referred to by name, not by its value (that is, no \textit{\$}). Generally, the variable would contain a well-formed, and optionally nested, paired list.

The \textit{node} argument is a well-formed Tcl list of zero or more items specifying the route to the item we're interested in.

For example:
\begingroup\small\begin{verbatim}
  set data {
       text    {ignored-data}
       valid-styles {
               justification {left centered right full}
               font          {courier helvetica times}
       }
  }

  puts "Justification: [pair get data {valid-styles justification}]"
\end{verbatim}
\endgroup

displays ``Justification: left centered right full''.

If the \textit{data} argument contains zero items, then the ``root'' node of the variable is targeted -{}- that is, the entire variable:
\begingroup\small\begin{verbatim}
  pair set node {} new-value
  puts $node
\end{verbatim}
\endgroup

displays ``new-value''.

If a non-existent node is targeted using the \textit{get} or \textit{unset} options, an error is returned:
\begingroup\small\begin{verbatim}
  unset x
  pair get x {first second third}
  -> no such value
\end{verbatim}
\endgroup

If a non-existent node is targeted using the \textit{set} or \textit{append} options, the node, and any parent nodes, are created.
\begingroup\small\begin{verbatim}
  unset x
  pair set x {first second third} value
  puts $x
\end{verbatim}
\endgroup

displays ``first \{second \{third value\}\}''

The \textit{exists} option mimics Tcl's \textit{info exists} command:
\begingroup\small\begin{verbatim}
  set x {name value}
  pair exists x name
  -> 1
  pair exists x name2
  -> 0
\end{verbatim}
\endgroup

The \textit{set} and \textit{append} 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's \textit{set} and \textit{append} commands' return values than duplicating the exact behaviour:
\begingroup\small\begin{verbatim}
  puts [pair set x {first second third} value]
\end{verbatim}
\endgroup

displays ``value''.

An error is returned if a variable is passed to the \textit{pair} command which doesn't contain a well-formed paired Tcl list at any point on the way to the node specified by the \textit{node} argument:
\begingroup\small\begin{verbatim}
  set x {name value thirdarg}
  pair get x name
  -> list must have an even number of elements
\end{verbatim}
\endgroup

If there are traces registered on the variable passed to the \textit{pair} command, they are triggered in the same manner as Tcl's \textit{set} and \textit{append} commands. Note that the \textit{append} option triggers only write triggers, not read triggers.

Note that the \textit{set} and \textit{append} options both return the value of the node specified, and the \textit{newValue} argument is optional in both cases, making the \textit{get} option redundant. The \textit{get} command is included to improve readability.

If the variable passed to \textit{pair} doesn't exist, it will be created if the option is 'set' or \textit{append}; the \textit{exists} option will always return a \textit{0}; the \textit{get} option will return an error.

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 \textit{array set}:
\begingroup\small\begin{verbatim}
  set x "name value1 name value2"
  pair get x name
  -> value2

  array set arrX $x
  set arrX(name)
  -> value2
\end{verbatim}
\endgroup

\section{Reference Implementation}

\url{http://sf.net/tracker/?func=detail&aid=491070&group_id=10894&atid=310894}

There should be a public C API for working with nested paired lists. The supplied reference code currently does not provide this.

\section{Notes}

It would be nice to mimic Tcl 8.4's new \textit{unset -nocomplain} behaviour.

\section{Side Effects}

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.

\section{Copyright}

This document has been placed in the public domain.

\section{Colophon}

\textit{TIP AutoGenerator --- written by Donal K. Fellows}
\begin{thebibliography}{TIP \#1}
\addcontentsline{toc}{section}{References}
\bibitem[TIP \#22]{tip22}
David Cuthbert,
Kevin Kenny,
Don Porter,
Donal K. Fellows,
\emph{Multiple Index Arguments to lindex},
on-line at \url{http://purl.org/tcl/tip/22.html}
\end{thebibliography}
\end{document}
