Tcl Part I · Module 6 · Lists
lappend: Growing a List
Most lists in real scripts are not written out in the source — they are collected as the script runs, one element at a time, as files are found or lines are parsed or results are computed. This is the command for that, and it is one of only two in the module that change a variable rather than returning a new value. It is also the right answer to a mistake that is very easy to make: the obvious alternative of reassigning the variable each time is not merely slower, it produces a list with the wrong number of elements.
Foundation11 min readTclPart IListsBuildingCorrectness
Part I · Module 6 · Chapter 6.6 · lappend
1. The Command
set found {}
lappend found "alpha"
lappend found "beta"
puts "$found -> [llength $found] elements"alpha beta -> 2 elementsIt takes a variable name — no $ — and adds to the end of the list it holds. Same shape as set, incr and append.
2. It Modifies the Variable
set l {a b}
linsert $l 0 header
puts "after linsert: $l"
lappend l "c"
puts "after lappend: $l"after linsert: a b
after lappend: a b clinsert returned a new list that was discarded. lappend changed l directly.
Only two commands in this module write to the variable: lappend and lset. Everything else returns a new list — a distinction Chapter 6.7 makes a point of.
3. It Quotes Correctly
This is Chapter 6.2's rule applied to growth:
set found {}
lappend found "two words"
lappend found "other"
puts "<$found> -> [llength $found] elements"
puts "element 0: <[lindex $found 0]>"<{two words} other> -> 2 elements
element 0: <two words>lappend added the braces. Two values in, two elements out, and the first one intact.
4. Several Values at Once
set found {}
lappend found "a" "b c" "d"
puts "$found -> [llength $found] elements"a {b c} d -> 3 elementsEach argument becomes one element, each quoted as needed.
5. The Mistake It Prevents
The obvious alternative:
set files {}
foreach f {report.txt "my notes.txt" data.csv} {
set files "$files $f"
}
puts "elements: [llength $files]"elements: 4Four, from three filenames. The one containing a space split into two elements — Chapter 6.2 §1 happening once per iteration.
set files {}
foreach f {report.txt "my notes.txt" data.csv} {
lappend files $f
}
puts "elements: [llength $files]"
puts "second: <[lindex $files 1]>"elements: 3
second: <my notes.txt>6. It Creates the Variable
lappend fresh "first"
puts "$fresh -> [llength $fresh] elements"first -> 1 elementsNo set fresh {} needed. Like incr in Chapter 3.9 §4 and append in Chapter 5.10 §4, a missing variable is treated as empty.
And the same caution: a typo in the variable name quietly starts a second list rather than failing. Initialise with set found {} anyway — it costs a line and makes the starting point visible.
7. It Returns the New List
set l {a}
puts "returns: [lappend l "b"]"
puts "l is: $l"returns: a b
l is: a bOccasionally useful, mostly ignored.
8. append and lappend Are Not the Same
set a {}
set b {}
lappend a "two words"
append b "two words"
puts "lappend: <$a> -> [llength $a] elements"
puts "append: <$b> -> [llength $b] elements"lappend: <{two words}> -> 1 elements
append: <two words> -> 2 elementslappend added one element and quoted it. append added characters, and the result happens to read as two elements.
The rule from Chapter 5.10 §8: append for text you will print, lappend for a collection you will take apart again.
9. The Collecting Shape
set matched {}
set skipped {}
foreach name {clk_tb reset data_tb payload} {
if {[string match "*_tb" $name]} {
lappend matched $name
} else {
lappend skipped $name
}
}
puts "matched ([llength $matched]): $matched"
puts "skipped ([llength $skipped]): $skipped"matched (2): clk_tb data_tb
skipped (2): reset payloadInitialise to empty, append as you go, report counts at the end. This is the list counterpart of the counter shape from Chapter 3.9 §6, and it is how most real lists come into existence.
10. Common Mistakes
set l "$l $v". Wrong and slow. §5.
Writing lappend $found $v. The name goes in without a $.
Using append where you meant lappend. §8.
Not initialising. It works; a typo then silently builds a second list. §6.
Appending a list expecting it to merge. lappend l $other adds the whole list as one element. To join two lists you want concat or lappend l {*}$other — Chapter 6.13.
11. Exercises
Exercise 1 — collect three. Build a list of three values with three lappend calls, then print it and its length.
Exercise 2 — several at once. Do the same with a single lappend taking three arguments, one of which contains a space. Confirm the length is 3.
Exercise 3 — reproduce the bug. Build a list of filenames with set files "$files $f" where one name has a space. Print the length, then fix it with lappend.
Exercise 4 — append versus lappend. Append the same two-word value to two empty variables, one with each command. Print both values and both lengths, and explain.
Exercise 5 — collect into two lists. Loop over six names and sort them into a matched list and a skipped list using string match, reporting both counts.
Exercise 6 — the merge trap. With set a {1 2} and set b {3 4}, predict the length after lappend a $b. Then produce a four-element list instead.
12. Remember
lappend varname value ...adds elements to a list variable, in place. No$on the name.- It is one of only two list commands that modify the variable — the other is
lset. - It quotes each value as one element, so a value containing spaces stays one element.
- It takes several values at once, creates a missing variable, and returns the new list.
set l "$l $v"is wrong before it is slow — it corrupts the element count and rebuilds the string every time.- Initialise with
set l {}anyway, so a typo cannot start a second list. appendadds characters;lappendadds elements.lappend l $otherlistadds one element. Use{*}to merge.
Next: inserting and removing elements anywhere in a list.
Where this fits
Part of the Tcl curriculum.
