Tcl Part I · Module 6 · Lists
{*} — Expanding a List Into Arguments
You have seen this a dozen times in the last few chapters, usually in a format call, and it is time it got its own treatment. It solves a problem that comes up constantly once you work with lists: you have the arguments for a command sitting in a list, and passing that list gives the command one argument rather than several. This is also the one piece of Tcl syntax that breaks the rule Module 2 spent a chapter establishing, which is worth understanding rather than memorising.
Intermediate11 min readTclPart IListsExecution ModelArguments
Part I · Module 6 · Chapter 6.13 · {*} — Expanding a List Into Arguments
1. The Problem
proc show {args} {
puts " received [llength $args] argument(s): $args"
}
set pair {alpha beta}
puts "without:"
show $pairwithout:
received 1 argument(s): {alpha beta}One argument, which happens to be a two-element list.
That is correct and it is Chapter 2.2 §4: a substituted value never changes how many words a command has. The source said show $pair — two words — so the command gets one argument.
But sometimes you have the arguments in a list and want them to be the arguments.
2. The Operator
proc show {args} {
puts " received [llength $args] argument(s): $args"
}
set pair {alpha beta}
puts "with:"
show {*}$pairwith:
received 2 argument(s): alpha betaTwo arguments. {*} tells Tcl to take the value and use its elements as separate words.
Note there is no space: {*}$pair, not {*} $pair.
3. It Is Syntax, Not a Command
{*} is not a list command. It is a piece of parser syntax, handled when Tcl is working out the words of a command — Chapter 2.2.
That matters because it means it works anywhere a command takes arguments, not only with list-related commands:
set spec {%-10s %4d}
set row {clk 1}
puts [format "[join $spec " "]" {*}$row]
set opts {-nocase "error*"}
puts [string match {*}$opts "ERROR: failed"]clk 1
1In the second, {*}$opts supplied both the -nocase flag and the pattern from a list — so which options a command receives can be decided at run time.
4. The Rule It Breaks
Chapter 2.2 §4 stated the rule:
What a substitution returns becomes part of a word. It never changes how many words there are.
And §8 of that chapter named the exception. This is it:
proc show {args} { puts "[llength $args] argument(s)" }
set three "a b c"
show $three
show {*}$three1 argument(s)
3 argument(s)The rule holds everywhere except here, and here you have to ask for it explicitly. That is the design: word boundaries are fixed by the source text, and the one way to change them is to write something that visibly says so.
5. It Replaces eval
Chapter 2.11 §4 made this argument; here is the evidence.
Suppose a command is built as a list:
set cmd [list puts "hello world"]
puts "the list: $cmd"
puts "elements: [llength $cmd]"the list: puts {hello world}
elements: 2Running it directly does not work, because the whole value is one word and therefore one command name:
set cmd [list puts "hello world"]
puts [catch {$cmd} message]
puts $message1
invalid command name "puts {hello world}"With {*}, the elements become the command and its argument:
set cmd [list puts "hello world"]
{*}$cmdhello world6. Where You Will Use It
Spreading a row into a formatted line — seen throughout Module 6:
set table {{clk 1 input} {payload 64 output}}
foreach row $table {
puts [format " %-10s %4d %s" {*}$row]
} clk 1 input
payload 64 outputMerging a list into another — Chapter 6.12 §4:
set a {1 2}
set b {3 4}
lappend a {*}$b
puts "$a -> [llength $a] elements"1 2 3 4 -> 4 elementsFlattening a table — Chapter 6.11 §8:
set table {{clk 1} {reset 1}}
puts [concat {*}$table]clk 1 reset 1Passing options decided at run time:
set sort_opts {-integer -decreasing}
set data {10 9 100}
puts [lsort {*}$sort_opts $data]100 10 9That last one is genuinely useful — a script can decide how to sort based on a configuration value, without an if for every combination.
7. Version Note
{*} requires Tcl 8.5 or later. Since the baseline for this track is 8.6 — Chapter 1.4 §4 — it is always available to you.
If you meet very old code using eval where {*} would do, that is usually why.
8. Common Mistakes
Writing {*} $value with a space. It must be attached: {*}$value.
Using it where you wanted one argument. lappend l {*}$other merges; lappend l $other adds one element. Both are correct for different intents.
Expecting it to parse text. It expands a list into words. It does not evaluate anything.
Reaching for eval instead. §5.
Expanding something that is not a well-formed list. The same error as Chapter 6.1 §5 — unbalanced braces cannot be expanded.
9. Exercises
Exercise 1 — one versus several. Using the show procedure from §1, pass a three-element list with and without {*}. Print both counts.
Exercise 2 — format a row. Build a two-row table and print each row with one format call using {*}. Then try it without and read the error.
Exercise 3 — merge. Merge two lists into one four-element list using lappend and {*}. Then show the three-element version without it.
Exercise 4 — the command list. Build [list puts "a message"], show that running it directly fails, and then run it with {*}.
Exercise 5 — runtime options. Write a script with a variable holding sort options, and sort the same data twice by changing only that variable.
Exercise 6 — eval versus expansion. Put the value {has $dollar} into a list and pass it to puts with {*}. Confirm the dollar sign is printed literally. Then say what eval would have done differently.
10. Remember
{*}$listpasses the list's elements as separate arguments. No space after{*}.- It is parser syntax, not a command, so it works with any command.
- It is the one exception to the rule that substitution never changes word boundaries — and you have to ask for it.
- It replaces
evalfor building commands.evalre-parses the text;{*}does not evaluate anything. - Build a command as a list and expand it.
- Common uses: spreading a row into
format, merging withlappend, flattening withconcat, and run-time options. - It needs Tcl 8.5 or later, so it is always available on this track's baseline.
One chapter remains, and it makes the format examples above even cleaner.
Where this fits
Part of the Tcl curriculum.
