Skip to content
VLSI Mentor

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

Azvya Education Pvt. Ltd.VLSI Mentor
difference.tcl
puts "list:   [list {a b} {c d}]"
puts "concat: [concat {a b} {c d}]"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
list:   {a b} {c d}
concat: a b c d

Same two arguments, different results.

Azvya Education Pvt. Ltd.VLSI Mentor
counts.tcl
puts "list elements:   [llength [list {a b} {c d}]]"
puts "concat elements: [llength [concat {a b} {c d}]]"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
list elements:   2
concat elements: 4

Two versus four.

  • list makes each argument one element. It nests.
  • concat opens 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?

Azvya Education Pvt. Ltd.VLSI Mentor
choosing.tcl
set inputs  {clk reset}
set outputs {payload status}

puts "merged:  [concat $inputs $outputs]"
puts "grouped: [list $inputs $outputs]"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
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:

Azvya Education Pvt. Ltd.VLSI Mentor
one-level.tcl
puts "input:  {{a b}} and {{c d}}"
puts "concat: [concat {{a b}} {{c d}}]"
puts "count:  [llength [concat {{a b}} {{c d}}]]"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
input:  {{a b}} and {{c d}}
concat: {a b} {c d}
count:  2

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

Azvya Education Pvt. Ltd.VLSI Mentor
merging.tcl
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"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
lappend a list: 1 2 {3 4} -> 3 elements
concat:         1 2 3 4 -> 4 elements
lappend {*}:    1 2 3 4 -> 4 elements

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

Azvya Education Pvt. Ltd.VLSI Mentor
whitespace.tcl
puts "<[concat "a " " b"]>"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
<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:

Azvya Education Pvt. Ltd.VLSI Mentor
flatten-table.tcl
set table {{clk 1} {reset 1} {payload 64}}

puts "rows:  [llength $table]"
puts "flat:  [concat {*}$table]"
puts "cells: [llength [concat {*}$table]]"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
rows:  3
flat:  clk 1 reset 1 payload 64
cells: 6

Note the {*}. Without it, concat $table receives one argument and flattens that one level, giving the rows back unchanged:

Azvya Education Pvt. Ltd.VLSI Mentor
without-expansion.tcl
set table {{clk 1} {reset 1}}

puts "concat \$table    -> [concat $table]"
puts "concat {*}\$table -> [concat {*}$table]"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
concat $table    -> {clk 1} {reset 1}
concat {*}$table -> clk 1 reset 1

The 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

  • list nests — each argument becomes one element.
  • concat flattens — 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?
  • concat flattens exactly one level and does not recurse.
  • lappend l $other adds one element; use concat or lappend l {*}$other to merge.
  • concat trims surrounding whitespace, which matters only when using it on text.
  • concat $table is not concat {*}$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.