Tcl Part I · Module 2 · The Tcl Execution Model
Newlines, Semicolons, and Command Boundaries
Every chapter so far has started from one command. This one asks where a command begins and ends. The answer is short — a newline or a semicolon ends it — but it has a consequence that every Tcl programmer meets in their first week: the opening brace of a body must be on the same line as the command it belongs to. That is not a style convention. It follows directly from the rule, and once you see why, the error it causes stops being mysterious.
Foundation11 min readTclPart IExecution ModelSyntaxErrors
Part I · Module 2 · Chapter 2.10 · Newlines, Semicolons, and Command Boundaries
1. What Ends a Command
Two things:
- a newline
- a semicolon
That is the whole rule. There is no statement terminator to remember, and no end keyword.
puts "first"
puts "second"Two lines, two commands. Each newline ended one.
2. Semicolons Put Two Commands on One Line
A semicolon does the same job as a newline, in the middle of a line:
set a 1 ; set b 2
puts "$a $b"1 2Three commands in two lines. The semicolon ended the first set.
You do not need semicolons at the end of lines. Writing puts "x"; is harmless but pointless — the newline already ended the command. Use a semicolon only when you genuinely want two commands on one line, which is mostly for short pairs like the one above.
3. A Newline Inside a Group Does Not End the Command
The rule has one qualification, and you have been relying on it since Module 1:
puts "first"
if {1 == 1} {
puts "inside"
puts "still inside"
}
puts "after"first
inside
still inside
afterThe if command spans four lines. Those newlines did not end it, because they are inside a braced word, and Tcl is still collecting that word.
So the accurate rule is: a newline ends a command when Tcl is between words. Inside quotes or braces, it is just a character being collected.
4. Continuing a Command Without Grouping
When a long command has no group to hide the newline in, use a backslash — Chapter 2.6 §4:
set items [list one \
two \
three]
puts $itemsone two three5. Why the Opening Brace Must Be on the Same Line
Now the consequence that catches everyone.
This is correct:
if {1 == 1} { puts "yes" }yesAnd this looks like the same thing in a different style:
if {1 == 1}
{ puts "yes" }wrong # args: no script following "1 == 1" argument
while executing
"if {1 == 1}"
(file "broken.tcl" line 1)Read what Tcl says. It ran if with one argument.
The newline after } ended the command. At that point if had received only a condition — no body. The next line, { puts "yes" }, became a separate command whose name is { puts "yes" }, but execution never reached it because if had already failed.
This is not Tcl being fussy about style. It is the boundary rule applied exactly: a newline between words ends the command, and the body is a word.
6. The Other Boundary Error
There is a second error people meet here, and it comes from a different mistake. It happens when something follows a closing brace with no space between them:
proc show {args} {
puts "received [llength $args] word(s)"
set i 1
foreach w $args {
puts " word $i: $w"
incr i
}
}
show {hello}worldextra characters after close-brace
while executing
"show {hello}world
"A braced word ends at its closing brace. The next character must be a space, a newline, or a semicolon — something that ends the word. world is none of those, so Tcl has characters it cannot place.
The same thing happens with set x {a}b.
There is no single fix, because the error means Tcl could not tell what you meant. Decide, then write it:
show {hello} world ;# two words
show {hello world} ;# one wordreceived 2 word(s)
word 1: hello
word 2: world
received 1 word(s)
word 1: hello worldWorth keeping the two errors apart:
| Message | What you did |
|---|---|
wrong # args: no script following ... | put the opening brace on the next line, so the command ended early |
extra characters after close-brace | wrote something immediately after a closing brace |
missing close-brace | never closed a brace at all |
7. A Stray Closing Brace
One more, because it reads strangely:
puts "one"
}one
invalid command name "}"
while executing
"}"
(file "stray.tcl" line 2)Tcl was between commands, so it read } as the start of one — and the first word of a command is a command name. There is no command called }.
This is almost always a leftover from deleting a block. The message is accurate but unhelpful on its own; now you know what it means.
8. Common Mistakes
Opening brace on the next line. §5. Comes from C or Java habits.
Something jammed against a closing brace. §6. Add a space.
Semicolons everywhere. Harmless, but it suggests the boundary rule has not landed.
Assuming a newline inside braces ends the command. It does not — §3.
Hunting for the wrong error. missing close-brace makes Tcl read to the end of the file, so the reported line is usually the last line, not the mistake. Count braces downward from the top of the block. Chapter 1.8 §6 covers the version of this caused by a brace inside a comment.
9. Exercises
Exercise 1 — three on one line. Rewrite these as a single line using semicolons, then confirm the output is unchanged:
set a 1
set b 2
puts "$a and $b"Exercise 2 — cause each error on purpose. Produce all three errors from the table in §6, one at a time, and read each message. Doing this once is what makes them recognisable later.
Exercise 3 — the brace rule. Write an if with the opening brace on the next line, run it, and read the error. Then fix it. Explain in one sentence what Tcl thought the if command's arguments were.
Exercise 4 — predict. Which of these run without error?
puts "a" ; puts "b"
puts {a}{b}
puts {a} {b}
puts "a"
}Exercise 5 — where does the command end? For the multi-line if in §3, say exactly which newline ended the if command. There is only one.
10. Remember
- A newline or a semicolon ends a command. There is no terminator to write.
- That only applies between words. Inside quotes or braces, a newline is an ordinary character.
- A semicolon is for two commands on one line, and it is what makes
;#work. - A backslash at the end of a line continues a command that has no group to span the newline.
- The opening brace of a body must be on the same line as the command — otherwise the newline ends the command and the body becomes a separate one.
wrong # args: no script followingmeans the brace was on the next line.extra characters after close-bracemeans something followed}with no space.- A lone
}is read as a command name.
One question remains, and it is the one that ties the module together: if Tcl substitutes once, what do you do when you genuinely need a second round?
Where this fits
Part of the Tcl curriculum.
