Tcl Part I · Module 3 · Values, Variables, and Expressions
expr: Arithmetic Is a Command, Not Syntax
Module 2 claimed that Tcl has almost no syntax and that nearly everything is a command. Arithmetic is where that claim becomes concrete and slightly startling. Plus and minus are not operators in Tcl — the language does not know what they are. There is a command called expr which understands a small expression language of its own, and arithmetic happens inside it. This chapter shows what follows from that, starting with a line that surprises everybody the first time they type it.
Foundation13 min readTclPart IValuesexprArithmetic
Part I · Module 3 · Chapter 3.7 · expr: Arithmetic Is a Command, Not Syntax
1. The Surprise
Type this and predict the output:
set x 1+1
puts $xMost people expect 2.
1+1Three characters, stored exactly as written. You can check:
set x 1+1
puts "stored: $x"
puts "length: [string length $x]"stored: 1+1
length: 3Nothing went wrong. set was given a name and a word, and it stored the word. The word happened to contain a plus sign, which is an ordinary character.
2. Tcl Does Not Do Arithmetic
That example is not a quirk to work around. It is the correct behaviour of a language in which + means nothing.
Chapter 2.1 said Tcl's grammar is one rule: a command and its words. There is no rule about operators, no precedence table in the parser, no arithmetic in the language at all.
So where does arithmetic come from? A command.
puts [expr {1 + 1}]2expr is an ordinary command. It takes an expression, works it out, and returns the answer. The brackets are command substitution — Chapter 2.5 — so the result becomes a word in the puts command.
3. Proof: + Is Not a Command Either
If + is not syntax, is it perhaps a command? No:
puts [catch {+ 1 1} m]
puts $m1
invalid command name "+"There is no command called +.
So the plus sign is neither Tcl syntax nor a Tcl command. It is part of a small language that expr understands and nothing else does. Tcl hands expr some text; expr parses that text with its own rules.
That is the whole mental model, and it explains everything else in this chapter and the next.
4. Using the Result
expr returns a value like any command, so you store or use it the usual ways:
set total [expr {4 * 5}]
puts "total = $total"
set width 8
puts "doubled = [expr {$width * 2}]"
puts "nested = [expr {[expr {2 + 3}] * 10}]"total = 20
doubled = 16
nested = 50The nested line works but is pointless — expr {(2 + 3) * 10} says the same thing. It is here only to show that expr is genuinely an ordinary command that can appear inside another command's words.
5. Always Brace the Expression
Every example on this page writes the expression inside braces:
expr {$width * 2} ;# do this
expr $width * 2 ;# not thisBrace the expression, always. It is correct, it is faster, and the next chapter — Chapter 3.8 — shows exactly what the unbraced form does wrong and why it is worth a chapter of its own.
For now treat it as a rule with a reason coming.
6. The Bareword Error
A mistake worth meeting now, because Tcl's message is unusually helpful:
set passed 7
puts [expr {passed + 1}]invalid bareword "passed"
in expression "passed + 1";
should be "$passed" or "{passed}" or "passed(...)" or ...Inside an expression, a bare name is not a variable. expr has its own rules, and in those rules passed on its own is meaningless — it is not a number and not a known function.
Tcl spotted the likely cause and told you the fix: write $passed. Add the dollar sign and it works:
set passed 7
puts [expr {$passed + 1}]8This is a common first-week error, especially for people arriving from languages where a bare identifier in an expression means a variable.
7. The Operators, Briefly
expr understands roughly what you would expect:
puts "add: [expr {7 + 3}]"
puts "subtract: [expr {7 - 3}]"
puts "multiply: [expr {7 * 3}]"
puts "divide: [expr {7 / 3}]"
puts "remainder:[expr {7 % 3}]"
puts "power: [expr {7 ** 3}]"add: 10
subtract: 4
multiply: 21
divide: 2
remainder:1
power: 343Look at the division line. 7 / 3 is 2, not 2.333. That is not a mistake and it is the subject of Chapter 3.10.
Comparison, logical and bitwise operators also live in expr, along with precedence rules and a set of maths functions. Module 4 is entirely about them, so this chapter stops at naming them.
8. Maths Functions
A small sample, since they come up alongside arithmetic:
puts "abs: [expr {abs(-7)}]"
puts "round: [expr {round(2.6)}]"
puts "max: [expr {max(3, 9, 4)}]"
puts "sqrt: [expr {sqrt(16)}]"abs: 7
round: 3
max: 9
sqrt: 4.0Note sqrt(16) is 4.0 and not 4 — a function that works in real numbers returns one. This matters when you print a result or compare it, and Chapter 3.10 covers why.
These are functions in expr's language, not Tcl commands. abs -7 on its own fails the same way + 1 1 did.
9. Common Mistakes
Expecting set x 1+1 to calculate. §1. It stores three characters.
Writing a bare variable name inside an expression. §6. Use $name.
Leaving the expression unbraced. §5, and Chapter 3.8 shows the damage.
Calling a maths function as a command. sqrt 16 is not a command; expr {sqrt(16)} is.
Expecting / to give a decimal. Chapter 3.10.
Using expr where you do not need it. incr adds one to a counter without an expression — Chapter 3.9 — and comparisons inside if already evaluate as expressions, which Module 8 covers.
10. Exercises
Exercise 1 — reproduce the surprise. Run set x 1+1 and print both the value and its length. Then produce 2 in the same script.
Exercise 2 — prove + is not a command. Run + 1 1 inside catch and print the message. Then do the same for sqrt 16. What do the two errors have in common?
Exercise 3 — meet the bareword error. Write expr {total * 2} with total set to 5. Read the message and apply the fix it suggests.
Exercise 4 — store and reuse. Set width to 12. Compute the area of a square of that width, store it in area, and print both. Use one expr only.
Exercise 5 — predict six. Before running, write down the answer for each:
puts [expr {9 / 2}]
puts [expr {9 % 2}]
puts [expr {2 ** 10}]
puts [expr {abs(-3.5)}]
puts [expr {round(0.5)}]
puts [expr {sqrt(9)}]Two of these may not match your first guess. Work out why.
Exercise 6 — explain it. A colleague asks why Tcl "makes you write expr". Answer in two sentences using §2 and §3, without saying that Tcl is old.
11. Remember
+,-,*and/are not Tcl syntax and not Tcl commands.+ 1 1fails withinvalid command name.- Arithmetic belongs to
expr, an ordinary command with its own small expression language. set x 1+1stores three characters. Nothing went wrong.exprreturns a value, so use it with command substitution:set total [expr {...}].- Always brace the expression. Chapter 3.8 explains why.
- A bare name inside an expression is an error — write
$name. Tcl's message tells you so. - Maths functions are part of
expr's language, not commands. 7 / 3is 2. Chapter 3.10.
Next: the one rule that makes expr both correct and fast, and the damage done without it.
Where this fits
Part of the Tcl curriculum.
