Skip to content
VLSI Mentor

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.

Azvya Education Pvt. Ltd.VLSI Mentor
boundaries.tcl
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:

Azvya Education Pvt. Ltd.VLSI Mentor
semicolon.tcl
set a 1 ; set b 2
puts "$a $b"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
1 2

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

Azvya Education Pvt. Ltd.VLSI Mentor
multiline.tcl
puts "first"
if {1 == 1} {
    puts "inside"
    puts "still inside"
}
puts "after"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
first
inside
still inside
after

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

Azvya Education Pvt. Ltd.VLSI Mentor
continued.tcl
set items [list one \
                two \
                three]

puts $items
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
one two three

5. Why the Opening Brace Must Be on the Same Line

Now the consequence that catches everyone.

This is correct:

Azvya Education Pvt. Ltd.VLSI Mentor
correct.tcl
if {1 == 1} { puts "yes" }
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
yes

And this looks like the same thing in a different style:

Azvya Education Pvt. Ltd.VLSI Mentor
broken.tcl
if {1 == 1}
{ puts "yes" }
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
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:

Azvya Education Pvt. Ltd.VLSI Mentor
extra.tcl
proc show {args} {
    puts "received [llength $args] word(s)"
    set i 1
    foreach w $args {
        puts "  word $i: $w"
        incr i
    }
}

show {hello}world
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
extra 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:

Azvya Education Pvt. Ltd.VLSI Mentor
fixed.tcl
show {hello} world     ;# two words
show {hello world}     ;# one word
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
received 2 word(s)
  word 1: hello
  word 2: world
received 1 word(s)
  word 1: hello world

Worth keeping the two errors apart:

MessageWhat you did
wrong # args: no script following ...put the opening brace on the next line, so the command ended early
extra characters after close-bracewrote something immediately after a closing brace
missing close-bracenever closed a brace at all

7. A Stray Closing Brace

One more, because it reads strangely:

Azvya Education Pvt. Ltd.VLSI Mentor
stray.tcl
puts "one"
}
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
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:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
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?

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
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 following means the brace was on the next line.
  • extra characters after close-brace means 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.