TIP 77: Support for Nested Paired Item Lists

Login
Bounty program for improvements to Tcl and certain Tcl packages.
Author:		Christian Williams <xian@planetoutpartners.com>
State:		Withdrawn
Type:		Project
Tcl-Version:	8.5
Vote:		Pending
Created:	07-Dec-2001
Obsoleted-By:	111
Post-History:	

Abstract

Tcl arrays can be transformed to and from lists using the array get and 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 [22].

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:

  set urlList { http tcl.activestate.com 80 /index.html }

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

Clearly the array approach promotes more readable code ($urlArray(host) versus [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:

  set data {
       text    {ignored-data}
       valid-styles {
               justification {left centered right full}
               font          {courier helvetica times}
       }
  }

Extracting items from structures like this can be accomplished by multiple array set commands:

  array set dataArray $data
  array set validStylesArray $dataArray(valid-styles)
  puts "Justification: $validStylesArray(justification)"

To modify an item in struct, we need some pretty ugly code:

  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]

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 dataArray and validStylesArray arrays first.

In contrast, a C programmer may expect that code to look more like this:

  data->valid-styles->justification = 'left';

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

Specification

Under this proposal, a new command named 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 array get command returns a well-formed paired list.

The syntax for the new pair command would be:

  pair option variable node ?newValue?

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

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

The 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:

  set data {
       text    {ignored-data}
       valid-styles {
               justification {left centered right full}
               font          {courier helvetica times}
       }
  }

  puts "Justification: [pair get data {valid-styles justification}]"

displays "Justification: left centered right full".

If the data argument contains zero items, then the "root" node of the variable is targeted -- that is, the entire variable:

  pair set node {} new-value
  puts $node

displays "new-value".

If a non-existent node is targeted using the get or unset options, an error is returned:

  unset x
  pair get x {first second third}
  -> no such value

If a non-existent node is targeted using the set or append options, the node, and any parent nodes, are created.

  unset x
  pair set x {first second third} value
  puts $x

displays "first {second {third value}}"

The exists option mimics Tcl's info exists command:

  set x {name value}
  pair exists x name
  -> 1
  pair exists x name2
  -> 0

The set and 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 set and append commands' return values than duplicating the exact behaviour:

  puts [pair set x {first second third} value]

displays "value".

An error is returned if a variable is passed to the pair command which doesn't contain a well-formed paired Tcl list at any point on the way to the node specified by the node argument:

  set x {name value thirdarg}
  pair get x name
  -> list must have an even number of elements

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

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

If the variable passed to pair doesn't exist, it will be created if the option is 'set' or append; the exists option will always return a 0; the 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 array set:

  set x "name value1 name value2"
  pair get x name
  -> value2

  array set arrX $x
  set arrX(name)
  -> value2

Reference Implementation

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.

Notes

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

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.

Copyright

This document has been placed in the public domain.

History