TIP #212: Temporarily Opening out a Dictionary
_____________________________________________________________________________
TIP:	212
Title:	Temporarily Opening out a Dictionary
Version:	$Revision: 1.9 $
Authors:	Donal K. Fellows <donal.k.fellows@man.ac.uk>
State:	Final
Type:	Project
Tcl-Version:	8.5
Vote:	Done
Created:	Wed Aug 11 00:00:00 UTC 2004
Keywords:	tcl, dict, update, script
Abstract
This TIP proposes a new subcommand of dict that associates variables with dictionary entries while a Tcl script (the "body" of the command) runs.
Rationale
The standard set of operations provided by the dict command (see [111] and [163]) give a fairly rich set of operations, but there are always further things that script authors want to do. Instead of ever-expanding numbers of subcommands offering tiny variants on existing operations, this TIP provides a generalized mechanism for associating variables and dictionary entries for the duration of a script. This makes writing arbitrary complex manipulations of dictionaries much simpler.
Proposed Change
This TIP proposes two new subcommands to dict, update and with, with the following syntaxes and semantics.
The 'dict update' Subcommand
dict update dictVarName dictKey varName ?dictKey varName ...? bodyScript
In prose, the first argument is the name of a variable containing a dictionary that will be updated, the last argument is a script to be executed with the variables set up and whose effects are expected to be to update the associated variables, and the other arguments between those two (of which there must be an even number, with a minimum of two) are a list of dictionary keys and the names of variables with which to associate those keys.
The semantics of the command are this:
1.	For each dictionary key (dictKey), the value from the dictionary contained in the variable named by dictVarName which that key maps to will be written to the variable associated with that key (varName). If the key is not present in the dictionary, the variable will be unset.
2.	The script (bodyScript) is executed.
3.	The dictionary is read out of dictVarName again and, for each dictKey, the varName variable is consulted and the contained value placed in the dictionary (if varName is unset, any existing mapping for dictKey will be removed.) Finally, the resulting dictionary value is written back to dictVarName.
If the dictVarName variable was unset (without being set to a new value) or otherwise rendered unreadable during the execution of bodyScript, the updating of the keys and writing back of the resulting dictionary to dictVarName is skipped. Note that it is only an unreadable dictVarName that is treated this way; it is an error for the variable to contain a value that is not a valid dictionary.
Note that dictVarName is read twice (each time, the value read must be a valid dictionary or the variable must be unset, which is interpreted as an empty dictionary) and (assuming the second read succeeds and returns a valid dictionary value) written once, and that no traces are set up; dictVarName is completely independent of the varNames during the execution of bodyScript.
Also note that step 3 is carried out even if bodyScript completes with a result code other than TCL_OK, and that the result code of the overall command will be the result code of the script unless TCL_ERROR was the result of the write-back stage, which might happen if the variable dictVarName is updated (during the execution of bodyScript) to contain a non-dictionary value, or if the variable dictVarName is either unset or cannot be written to (which can happen if a write trace throws an error); note that this mandates that any errors from the bodyScript are lost if the write-back phase also throws an error. If the result code is TCL_OK, the result string/object will be whatever the result string/object of bodyScript was.
The 'dict with' Subcommand
dict with dictVarName ?key ...? bodyScript
This is a shorthand version of dict update (named after the Pascal with keyword) which maps all of the keys in the dictionary in the variable dictVarName to variables during the evaluation of bodyScript. Note that it builds a list of all the keys in the dictionary before bodyScript runs and only those variables which are created are mapped back at the end; if extra keys are defined in the dictionary in the variable during the execution of bodyScript, they will be left alone when bodyScript finishes.
The variables will be written to and read from in the natural order of the keys of the dictionary in the variable dictVarName when the dict with command starts.
When a key (or several keys) is provided, it describes a path into a nested set of dictionaries (much like with dict set) where the selected leaf indicates a dictionary that is to be opened out. When writing back, non-existence of any key on the path is treated the same as if dictVarName itself didn't exist.
Examples
A somewhat-less-efficient version of dict set:
 dict update someVar $key local 
     set local $value
 
Sorting a list inside a nested dictionary:
 dict update someVar OuterKey temp 
     dict update temp InnerKey temp2 
         set temp2 [lsort $temp2]

"Renaming" a key:
 dict update someVar oldKey foo newKey bar 
     set bar $foo
     unset foo
 
Opening out a nested dictionary:
 dict update someVar OuterKey temp 
     dict with temp 
         # Some script goes in here...

 # Alternative version using a key with 'dict with'...
 dict with someVar OuterKey 
     # Some script goes in here...  
 
Reference Implementation
See SF patch 1008768[http://sf.net/tracker/?func=detail&aid=1008768&group_id=10894&atid=310894].
Copyright
This document has been placed in the public domain.
_____________________________________________________________________________
Colophon
TIP AutoGenerator - written by Donal K. Fellows