Tcl Part I · Module 6 · Lists
concat vs list: The Flattening Difference
Two commands take several lists and give you one list back, and they do different things with them. One keeps each argument as a single element; the other opens each argument up and merges its contents. Both produce a perfectly valid list, so picking the wrong one does not fail — it quietly gives you a different number of elements than you expected, and the problem surfaces somewhere else entirely. The difference takes one example to see and is worth being certain about.
Foundation10 min readTclPart IListsCombining
Part I · Module 6 · Chapter 6.12 · concat vs list
1. The Difference, in One Example
puts "list: [list {a b} {c d}]"
puts "concat: [concat {a b} {c d}]"list: {a b} {c d}
concat: a b c dSame two arguments, different results.
puts "list elements: [llength [list {a b} {c d}]]"
puts "concat elements: [llength [concat {a b} {c d}]]"list elements: 2
concat elements: 4Two versus four.
listmakes each argument one element. It nests.concatopens each argument up and merges the contents. It flattens.
2. Which One Do You Want?
Are the arguments items to collect, or lists to merge?
set inputs {clk reset}
set outputs {payload status}
puts "merged: [concat $inputs $outputs]"
puts "grouped: [list $inputs $outputs]"merged: clk reset payload status
grouped: {clk reset} {payload status}The first is one list of four signals. The second is a list of two groups.
Both are useful; they are answers to different questions.
3. It Flattens Exactly One Level
This is the part worth being precise about:
puts "input: {{a b}} and {{c d}}"
puts "concat: [concat {{a b}} {{c d}}]"
puts "count: [llength [concat {{a b}} {{c d}}]]"input: {{a b}} and {{c d}}
concat: {a b} {c d}
count: 2Each argument was a list containing one element. concat removed one level, so the results are the inner lists — which are still lists.
"Flattens" without "one level" leaves people expecting a b c d. It does not recurse, and there is no option to make it.
4. Merging a List Into a Variable
The common need, and three ways to do it:
set a {1 2}
set b {3 4}
set wrong $a
lappend wrong $b
set right1 [concat $a $b]
set right2 $a
lappend right2 {*}$b
puts "lappend a list: $wrong -> [llength $wrong] elements"
puts "concat: $right1 -> [llength $right1] elements"
puts "lappend {*}: $right2 -> [llength $right2] elements"lappend a list: 1 2 {3 4} -> 3 elements
concat: 1 2 3 4 -> 4 elements
lappend {*}: 1 2 3 4 -> 4 elementslappend adds one element, which is Chapter 6.6 §10. If you wanted the contents merged, use concat or {*} — Chapter 6.13.
5. concat Also Tidies Whitespace
A detail that explains why concat is sometimes described as a string operation:
puts "<[concat "a " " b"]>"<a b>It trimmed the surrounding whitespace from each argument before joining with a single space.
That is harmless for well-formed lists and is worth knowing if you ever use concat on text rather than lists. For joining text you want join or append, both of which do exactly what you tell them.
6. Flattening a Table
From Chapter 6.11 §8:
set table {{clk 1} {reset 1} {payload 64}}
puts "rows: [llength $table]"
puts "flat: [concat {*}$table]"
puts "cells: [llength [concat {*}$table]]"rows: 3
flat: clk 1 reset 1 payload 64
cells: 6Note the {*}. Without it, concat $table receives one argument and flattens that one level, giving the rows back unchanged:
set table {{clk 1} {reset 1}}
puts "concat \$table -> [concat $table]"
puts "concat {*}\$table -> [concat {*}$table]"concat $table -> {clk 1} {reset 1}
concat {*}$table -> clk 1 reset 1The first flattened the outer level of a single argument — which is the table itself — so nothing visible changed. The second passed three separate arguments, each of which got flattened.
That distinction is the clearest motivation for the next chapter.
7. Common Mistakes
Using list when you meant to merge. You get a list of lists.
Using concat when you meant to group. You lose the structure.
Expecting concat to flatten completely. One level only. §3.
lappend l $otherlist. Adds one element. §4.
concat $listvar expecting the elements. It needs {*}. §6.
Using concat to join text. Use join or append. §5.
8. Exercises
Exercise 1 — two versus four. Run both commands on {a b} and {c d} and print the element counts. Say in one sentence what each did.
Exercise 2 — one level. Predict the result and count for concat {{x y}} {{z}}. Then check.
Exercise 3 — merge three ways. With set a {1 2} and set b {3 4}, produce a four-element list using concat, and again using lappend with {*}. Then show the three-element version that lappend $b gives.
Exercise 4 — group then flatten. Build a list of three two-element groups with list, print the count, then flatten it back to six elements.
Exercise 5 — the missing expansion. Run concat $table and concat {*}$table on a three-row table and explain why they differ.
Exercise 6 — pick the command. For each: combining two lists of filenames into one; storing inputs and outputs as two named groups; building a row of three fields; turning a table into a flat list of cells.
9. Remember
listnests — each argument becomes one element.concatflattens — each argument is opened up and merged.- Both produce valid lists, so choosing wrong changes the count with no error.
- Ask: items to collect, or lists to merge?
concatflattens exactly one level and does not recurse.lappend l $otheradds one element; useconcatorlappend l {*}$otherto merge.concattrims surrounding whitespace, which matters only when using it on text.concat $tableis notconcat {*}$table— the first sees one argument.
Next: the operator that turned up in half the examples above.
Where this fits
Part of the Tcl curriculum.
