Tcl Part I · Module 2 · The Tcl Execution Model
Braces: Grouping Without Substitution
Braces group text into one word, like quotes do, but they do not let substitutions run inside. Most explanations stop there, which makes braces sound like a defensive measure for when you want to avoid something. That framing never explains why real Tcl code is full of them. The real reason is positive: braces are how a block of code reaches a command unchanged, so the command can decide whether to run it and when. Every command in Tcl that takes a body of code depends on this.
Foundation12 min readTclPart IExecution ModelGroupingBraces
Part I · Module 2 · Chapter 2.8 · Braces: Grouping Without Substitution
1. What They Do
Braces group text into one word, and nothing inside is substituted:
set name Maya
puts "Hello, $name"
puts {Hello, $name}Hello, Maya
Hello, $nameSame characters inside. The quoted version substituted $name. The braced version passed the two characters $name straight through.
Brackets behave the same way:
puts "length is [string length hello]"
puts {length is [string length hello]}length is 5
length is [string length hello]In the braced version, the command inside the brackets never ran.
2. Braces Group, Exactly Like Quotes
Before the differences, the thing they share. Braces make one word:
proc show {args} {
puts "received [llength $args] word(s)"
set i 1
foreach w $args {
puts " word $i: $w"
incr i
}
}
show {my report.txt}received 1 word(s)
word 1: my report.txtOne word, same as "my report.txt" would give. Grouping is the job both forms do. What differs is what happens inside.
3. What Gets Through Unchanged
Everything that would otherwise be special:
puts {a dollar $here, brackets [here], and a quote " here}a dollar $here, brackets [here], and a quote " hereNo escaping needed for any of it. This is the easiest way to produce text containing Tcl's special characters — compare the escaping you needed in Chapter 2.6.
4. Braces Nest
An inner pair of braces does not end the group:
show {outer {inner} outer}received 1 word(s)
word 1: outer {inner} outerTcl matched the outer braces by counting. The inner pair came through as ordinary characters.
This matters more than it looks. Every block of real code contains braces, so a body could not be passed as one word at all if nesting did not work.
5. The Real Purpose: Code as Data
Now the part that explains idiomatic Tcl.
Chapter 2.1 §5 showed a command receiving a body of code as a plain word, unrun. Braces are what made that possible. Here it is with a real command:
foreach x {1 2 3} {
puts "x is $x"
}x is 1
x is 2
x is 3Look at what foreach received: two braced words. The first, {1 2 3}, is the list to walk. The second is the body.
The body contains $x. If it had been substituted when the line was read, $x would have had no value yet and the command would have failed. Instead the body arrived as text, and foreach ran it three times — setting x before each run.
That is why the body is braced. Not to avoid substitution, but to delay it until the command is ready.
Now the same idea with if, which you have been writing since Module 1:
set count 0
if {$count == 0} {
puts "nothing to do"
}nothing to doBoth braced words are deferred. if evaluates the first when it wants a true or false answer, and runs the second only if the answer is true. Neither could work if Tcl had substituted them on the way in.
6. When Braces Are the Wrong Choice
Braces are not always better. If you want a value in your text, braces stop you getting it:
set name Maya
puts {Hello, $name}Hello, $nameThat is a bug if you wanted the name. Nothing errors — you simply get the wrong text, which is harder to notice than a crash.
The choice between the two forms is Chapter 2.9, the next chapter.
7. The One Exception
Braces stop variable substitution and command substitution. They do not stop a backslash at the end of a line from joining it to the next.
Chapter 2.6 §6 proves this and explains the consequence. The accurate rule is:
Braces stop the substitutions that insert values —
$and[ ]. A backslash-newline still joins lines.
Worth stating precisely, because "braces change nothing" is the version most people carry, and it is wrong in exactly one place.
8. Common Mistakes
Using braces when you wanted a value. §6. No error, wrong text.
Thinking braces are "safer". They are not safer or stricter. They are a different instruction. Using them everywhere breaks every message that needs a variable.
Forgetting a closing brace. You get missing close-brace, and because Tcl keeps reading to the end of the file looking for it, the reported line is often the last line rather than the mistake. Count braces from the top.
Putting a lone brace in a comment. It still counts. That is Chapter 1.8 §6, and Tcl has a dedicated error message for it.
Expecting \n to work inside braces. It does not. {a\nb} is four characters. Use quotes when you want escape sequences processed.
9. Exercises
Exercise 1 — predict both forms. With set n 5, write down what each prints:
puts "n is $n"
puts {n is $n}
puts "total [expr {$n + 1}]"
puts {total [expr {$n + 1}]}Exercise 2 — produce awkward text. Write one puts that prints exactly this, using braces rather than escaping:
use $name and [command] carefullyThen write it again with quotes and backslashes. Which is easier to read?
Exercise 3 — break a body. Run this, which is the §5 example with a quoted body instead of a braced one:
set x PRESET
foreach x {1 2 3} "puts \"x is $x\""Predict the three lines first. The result is worth seeing: the body was substituted once, when the line was read, so every iteration prints the same thing. Explain why using §5.
Exercise 4 — count the characters. Predict, then check:
puts [string length "a\tb"]
puts [string length {a\tb}]Exercise 5 — the nesting question. How many words is show {a {b} c} d? Predict, then run it.
10. Remember
- Braces group text into one word, exactly as quotes do.
- Nothing inside is substituted —
$nameand[command]pass through as characters. - Braces nest, so a body full of braces still arrives as one word.
- Their real purpose is deferring code. A body reaches a command unchanged, and the command decides when to run it.
- That is why
if,foreach,whileandprocall take braced bodies. - They are not "safer" than quotes. Using them when you wanted a value gives wrong text with no error.
- One exception: a backslash at the end of a line still joins lines. Chapter 2.6 §6.
Next: how to choose between the two, in one rule.
Where this fits
Part of the Tcl curriculum.
