| [ Team LiB ] |
|
Constructing ListsConstructing a list can be tricky if you try to write the proper list syntax by hand. The manual approach works for simple cases. In more complex cases, however, you should use Tcl commands that build lists. Using list commands eliminates the struggle to get the grouping and quoting right, and the list is maintained in an efficient internal format. If you create lists by hand with quoting, there is additional overhead to parse the string representation the first time you use the list. The list commandThe list command constructs a list out of its arguments so that there is one list element for each argument. The simple beauty of list is that any special characters in the list elements do not matter. Spaces inside an element do not cause it to become more than one list element. The list command is efficient, too. It doesn't matter if list is making a list of three single-character values, or three 10 kilobyte values. The cost to make that three element list is the same in either case. The most compelling uses of list involve making lists out of variables that could have arbitrary values, as shown in Example 5-1. Example 5-1 Constructing a list with the list command
set x {1 2}
=> 1 2
set y \$foo
=> $foo
set l1 [list $x "a b" $y]
=> {1 2} {a b} {$foo}
set l2 [list $l1 $x]
=> {{1 2} {a b} {$foo}}} {1 2}
The first list, l1, has three elements. The values of the elements do not affect the list structure. The second list, l2, has two elements, the value of l1 and the value of x. Internally Tcl shares values instead of making copies, so constructing lists out of other values is quite efficient. When you first experiment with Tcl lists, the treatment of curly braces can be confusing. In the assignment to x, for example, the curly braces disappear. However, they seem to come back again when $x is put into a bigger list. Also, the double quotes around a b get changed into curly braces. What's going on? There are three steps in the process. In the first step, the Tcl parser groups arguments to the list command. In the grouping process, the braces and quotes are syntax that define groups. These syntax characters get stripped off. The braces and quotes are not part of the values being grouped. In the second step, the list command creates an internal list structure. This is an array of references to each value. In the third step the value is printed out. This step requires conversion of the list into a string representation. The string representation of the list uses curly braces to group values back into list elements. The lappend CommandThe lappend command is used to append elements to the end of a list. The first argument to lappend is the name of a Tcl variable, and the rest of the arguments are added to the variable's value as new list elements. Like list, lappend operates efficiently on the internal representation of the list value. It is always more efficient to use lappend than to try and append elements by hand. Example 5-2 Using lappend to add elements to a listlappend new 1 2 => 1 2 lappend new 3 "4 5" => 1 2 3 {4 5} set new => 1 2 3 {4 5} The lappend command is unique among the list-related commands because its first argument is the name of a list-valued variable, while all the other commands take list values as arguments. You can call lappend with the name of an undefined variable and the variable will be created. The lset CommandThe lset command was introduced in Tcl 8.4 to make it easier, and more efficient, to set one element of a list or nested list. Like lappend, the first argument to lset is the name of a list variable. The last argument is the value to set. The middle arguments, if any, specify which element to set. If no index is specified, the whole variable is set to the new value. If the index is a single integer, or end-integer, then that element of the list is set. If you have a nested list, then you can specify several indices, and each one navigates into the nested list structure. This is illustrated in Example 5-3. If you specify several indices they can be separate arguments, or grouped into a list. Range checking in lset is strict and an error will be thrown for indices given outside of the list or sublist range. The new value of the list in the variable is returned, although you rarely need this because lset modifies the list variable directly. Example 5-3 Using lset to set an element of a listlset new "a b c" => a b c lset new 1 "d e" => a {d e} c lset new 1 0 "g h" => a {{g h} e} c The concat CommandThe concat command is useful for splicing lists together. It works by concatenating its arguments, separating them with spaces. This joins multiple lists into one list where the top-level list elements in each input list become top-level list elements in the resulting list: Example 5-4 Using concat to splice lists together
set x {4 5 6}
set y {2 3}
set z 1
concat $z $y $x
=> 1 2 3 4 5 6
Double quotes behave much like the concat command. In simple cases, double quotes behave exactly like concat. However, the concat command trims extra white space from the end of its arguments before joining them together with a single separating space character. Example 5-5 compares the use of list, concat, and double quotes: Example 5-5 Double quotes compared to the concat and list commands
set x {1 2}
=> 1 2
set y "$x 3"
=> 1 2 3
set y [concat $x 3]
=> 1 2 3
set s { 2 }
=> 2
set y "1 $s 3"
=> 1 2 3
set y [concat 1 $s 3]
=> 1 2 3
set z [list $x $s 3]
=> {1 2} { 2 } 3
The distinction between list and concat becomes important when Tcl commands are built dynamically. The basic rule is that list and lappend preserve list structure, while concat (or double quotes) eliminates one level of list structure. The distinction can be subtle because there are examples where list and concat return the same results. Unfortunately, this can lead to data-dependent bugs. Throughout the examples of this book, you will see the list command used to safely construct lists. This issue is discussed more in Chapter 10. |
| [ Team LiB ] |
|