Skip to content
VLSI Mentor

Tcl Part I · Module 6 · Lists

Building a List: list vs Writing Braces by Hand

If a list is just a string, it is tempting to build one by gluing text together with quotes. That works right up until a value contains a space, at which point the list quietly has more elements than you put in it and nothing reports a problem. This chapter shows that failure, shows what the list command does instead — including a case where it reaches for an escaping form you would never have written by hand — and is honest about the one situation where typing the braces yourself is exactly right.

Foundation12 min readTclPart IListsConstructionCorrectness

Part I · Module 6 · Chapter 6.2 · Building a List

1. The Tempting Mistake

A list is a string, so this looks reasonable:

Azvya Education Pvt. Ltd.VLSI Mentor
tempting.tcl
set name "alpha"
set bad "$name other"

puts "<$bad> -> [llength $bad] elements"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
<alpha other> -> 2 elements

It works. Two values in, two elements out.

Now the same code with a value that contains a space:

Azvya Education Pvt. Ltd.VLSI Mentor
broken.tcl
set name "two words"
set bad "$name other"

puts "<$bad> -> [llength $bad] elements"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
<two words other> -> 3 elements

Three elements. You supplied two values and got three.

No error. The string is a perfectly valid list — it just is not the list you meant. The space inside the value became a separator, because the value was placed into the text with nothing marking where it began and ended.

2. What list Does

Azvya Education Pvt. Ltd.VLSI Mentor
correct.tcl
set name "two words"
set good [list $name other]

puts "<$good> -> [llength $good] elements"
puts "element 0: <[lindex $good 0]>"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
<{two words} other> -> 2 elements
element 0: <two words>

Two elements, and the first one is the whole value.

Look at what list produced: {two words} other. It added the braces. You did not write them; list worked out that the first value needed grouping and supplied it.

That is the command's entire job — take values, produce a string in which each value is one element, adding whatever quoting that requires.

3. It Quotes Only What Needs It

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

Plain values are left alone. A value with a space gets braces. An empty value gets {}, because otherwise it would vanish entirely.

4. And It Handles Cases You Would Get Wrong

Here is where the argument becomes unarguable. What if a value contains a brace?

Azvya Education Pvt. Ltd.VLSI Mentor
brace-value.tcl
puts [list "has {brace" x]
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
has\ \{brace x

list did not use braces — it could not, because the value contains an unbalanced one. It switched to backslash escaping, and the result is still a valid two-element list:

Azvya Education Pvt. Ltd.VLSI Mentor
brace-value-check.tcl
set l [list "has {brace" x]

puts "elements: [llength $l]"
puts "first:    <[lindex $l 0]>"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
elements: 2
first:    <has {brace>

Two elements, and the first is exactly the original value, brace and all.

5. Braced Literals Are Fine

The rule is about values, not about syntax. When you are typing a fixed list into your source, braces are correct and idiomatic:

Azvya Education Pvt. Ltd.VLSI Mentor
literal.tcl
set modes {fast slow careful}

puts "[llength $modes] elements: $modes"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
3 elements: fast slow careful

Nobody writes [list fast slow careful] for that, and nobody should. There is nothing to substitute, so there is nothing that can go wrong.

The distinction:

Azvya Education Pvt. Ltd.VLSI Mentor
distinction.tcl
set name "two words"

set literal {alpha beta}
set from_values [list $name "other value"]

puts "literal:     [llength $literal] elements"
puts "from values: [llength $from_values] elements"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
literal:     2 elements
from values: 2 elements

And remember from Chapter 2.8 that braces do not substitute:

Azvya Education Pvt. Ltd.VLSI Mentor
no-substitution.tcl
set name "alpha"
set wrong {$name other}

puts "element 0: <[lindex $wrong 0]>"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
element 0: <$name>

The literal characters $name, not the value. If you want the value, you need list.

Braces for fixed text you type. list for anything that came from a variable.

6. Growing a List

For adding to an existing list, lappend does the same quoting:

Azvya Education Pvt. Ltd.VLSI Mentor
lappend.tcl
set found {}

lappend found "two words"
lappend found "other"

puts "<$found> -> [llength $found] elements"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
<{two words} other> -> 2 elements

Same braces, same correctness. Chapter 6.6 covers it properly; it is mentioned here because set found "$found $value" is the same mistake as §1 and is easy to reach for in a loop.

7. Building a List of Lists

list nests cleanly, because each value is quoted as one element:

Azvya Education Pvt. Ltd.VLSI Mentor
nesting.tcl
set row1 [list clk 1]
set row2 [list "data bus" 64]

set table [list $row1 $row2]

puts "table:    $table"
puts "rows:     [llength $table]"
puts "row 1:    <[lindex $table 1]>"
puts "its name: <[lindex $table 1 0]>"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
table:    {clk 1} {{data bus} 64}
rows:     2
row 1:    <{data bus} 64>
its name: <data bus>

Two rows, and the two-word name survived two levels of nesting without you writing a single brace. Chapter 6.11 covers nesting properly.

8. Common Mistakes

set l "$a $b". The classic. §1.

set l "$l $new" in a loop. Same mistake, repeated. Use lappend. §6.

Writing braces around a variable: {$name} is the literal text $name. §5.

Using list for a fixed literal. Correct but noisy. §5.

Assuming a value "won't have spaces". Filenames, descriptions, names and error messages all do, eventually.

Reading the braces in output as data. {two words} is Tcl showing you one element that contains a space. lindex returns it without them.

9. Exercises

Exercise 1 — reproduce the corruption. Build a two-value list with "$a $b" where one value has a space. Print the element count. Then fix it with list.

Exercise 2 — watch the quoting. Print the result of list for these argument sets, and explain each: a b, "a b" c, "" a, a "b{c".

Exercise 3 — literal or list. For each, say which to use: a fixed set of three mode names; a pair of values read from a line; a list of column headings you type; a filename plus a size.

Exercise 4 — the brace value. Build a list whose first element is the text a{b. Confirm with llength and lindex that it is one element and the value is intact.

Exercise 5 — nest it. Build a two-row table where one cell contains two words, using only list. Then pull that cell out with one lindex.

Exercise 6 — spot the bug. This builds a list of filenames and is wrong. Say why, and fix it:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
set files {}
foreach f {report.txt "my notes.txt" data.csv} {
    set files "$files $f"
}
puts [llength $files]

10. Remember

  • A value placed into text with no quoting loses its boundaries. "$name other" with a two-word name gives three elements.
  • Nothing errors. The result is a valid list with the wrong contents.
  • list adds whatever quoting each value needs — braces, or backslashes when braces will not work.
  • It quotes only what needs it, and gives an empty value {} so it does not vanish.
  • Braced literals are correct for fixed text you type. Braces do not substitute, so {$name} is literal.
  • The rule: braces for literals, list for values.
  • lappend does the same quoting when growing a list.
  • Braces in printed output are Tcl showing element boundaries, not data.

Next: counting what you have built.

Where this fits

Part of the Tcl curriculum.