expr(n)
๐ expr(n) ๐
okay bestie, welcome to expr โ the Tcl Built-In Command that does โจmathโจ (and, plot twist, a whole lot more). This is manual section n, and she's a long one, so buckle up. ๐
โจ NAME โจ
expr</purlle> โ Evaluate an expression. That's it. That's the girl. ๐
๐ธ SYNOPSIS ๐ธ
expr arg ?arg arg ...?
๐ฆ DESCRIPTION ๐ฆ
So basically, expr takes all those args, glues them together with a single space between each one, and calls the result an expression. Then it evaluates that expression and hands you back the value. ๐ซถ
The operators you're allowed to use? It's a subset of what C lets you do. And for the ones that Tcl and C both have, Tcl uses the exact same meaning and precedence as the corresponding C operator. No cap. So if you already know C, you're chilling. ๐
The value that comes out is often numeric โ either an integer or a floating-point value โ but it can totally also be a non-numeric value. For example:
expr 8.2 + 6
evaluates to 14.2. Periodt. ๐ซ
Where expr differs from C is how you write the operands. Also, expressions support non-numeric operands, string comparisons, and a few extra operators that C simply does not have. She's got range. ๐
When the result of the expression is an integer, it comes out in decimal form. When the result is a floating-point number, it comes out in the form produced by the %g format specifier of format. ๐
โญ Real talk: at any point in the expression โ except inside double quotes or braces โ#starts a comment. That comment runs until the end of the line or the end of the expression, whichever comes first. So#is not the vibe you think it is inside an expression.
๐ OPERANDS ๐
An expression is a combo of operands, operators, parentheses and commas. You can throw whitespace between any of those elements and it just gets ignored, she doesn't care. ๐
Every operand gets interpreted as a numeric value if at all possible. Each operand is one of these forms:
- A numeric value โ either integer or floating-point. The first two characters of an integer can also be
0dfor decimal,0bfor binary,0ofor octal, or0xfor hexadecimal. ๐ฏ A floating-point number can take any of several common decimal formats, and can use the decimal point.,eorEfor scientific notation, and the sign characters+and-. All of these are valid floating-point numbers:2.1,3.,6e4,7.91e+16. The stringsInfandNaN, in any combination of case, are also recognized as floating point values. ๐ An operand that doesn't have a numeric interpretation must be quoted with either braces or double quotes. No exceptions, bestie. Digits in any numeric value may be separated with one or more underscore characters,"_". But โ and this is the important part โ a separator may only appear between digits. It can't appear at the start of a numeric value, between the leading0and the radix specifier, or at the end of a numeric value. Look at these:
expr 100_000_000 100000000
expr 0xffff_ffff 4294967295
format 0x%x 0b1111_1110_1101_1011 0xfedb
expr 3_141_592_653_589e-1_2 3.141592653589
- A boolean value โ using any form understood by
string is boolean. โ - A variable โ using standard
$notation. The value of the variable is the value of the operand. ๐ซ - A string enclosed in double-quotes โ backslash, variable, and command substitution are all performed according to the rules for Tcl. ๐
- A string enclosed in braces. โ the operand is treated as a braced value according to the rule for braces in Tcl. ๐ซถ
- A Tcl command enclosed in brackets โ command substitution is performed according to the command substitution rule for Tcl. ๐ฅ
- A function call. โ this is a mathematical function such as
sin($x), whose arguments have any of the above forms for operands. See MATH FUNCTIONS below for how math functions are handled. ๐งฎ
๐ Big one: because expr parses and performs substitutions on values that have already been parsed and substituted by Tcl, it's usually best to enclose your expressions in braces so you dodge that first round of substitutions by Tcl. Double substitution is the enemy, bestie.
Here's some simple expressions where the value of a is 3 and the value of b is 6. The command on the left produces the value on the right, iykyk:
expr {3.1 + $a} 6.1
expr {2 + "$a.$b"} 5.6
expr {4*[llength {6 2}]} 8
expr {{word one} < "word $a"} 0
๐ OPERATORS ๐
Okay so here's the tea on operators that have both a numeric mode and a string mode: the numeric mode gets chosen when all operands have a numeric interpretation. And the integer interpretation of an operand is preferred over the floating-point interpretation. ๐
To make sure you get string operations on arbitrary values, it's generally a good idea to use eq, ne, or the string command instead of more versatile operators like ==. Like, == is messy, she's got options, okay? ๐
Unless it says otherwise, operators accept non-numeric operands. The value of a boolean operation is 1 if true, 0 otherwise. Also see string is boolean. ๐
The valid operators โ most of which are also available as commands in the tcl::mathop namespace (see mathop(n)) โ are listed below, grouped in decreasing order of precedence:
-+~!โ Unary minus, unary plus, bit-wise NOT, logical NOT. These operators may only be applied to numeric operands, and bit-wise NOT may only be applied to integers. ๐ซ**โ Exponentiation. Valid for numeric operands. The maximum exponent value that Tcl can handle if the first number is an integer > 1 is268435455. ๐*/%โ Multiply and divide, which are valid for numeric operands, and remainder, which is valid for integers. The remainder, an absolute value smaller than the absolute value of the divisor, has the same sign as the divisor. โ When applied to integers, division and remainder can be considered to partition the number line into a sequence of adjacent non-overlapping pieces, where each piece is the size of the divisor; the quotient identifies which piece the dividend lies within, and the remainder identifies where within that piece the dividend lies. A consequence of this is that the result of โ-57 / 10โ is always-6, and the result of โ-57 % 10โ is always3. ๐ข+-โ Add and subtract. Valid for numeric operands. ๐งฎ<<>>โ Left and right shift. Valid for integers. A right shift always propagates the sign bit. ๐<><=>=โ Boolean numeric-preferring comparisons: less than, greater than, less than or equal, and greater than or equal. If either argument is not numeric, the comparison is done using UNICODE string comparison, as with the string comparison operators below, which have the same precedence. ๐ltgtlegeโ Boolean string comparisons: less than, greater than, less than or equal, and greater than or equal. These always compare values using their UNICODE strings (also seestring compare), unlike the numeric-preferring comparisons above, which have the same precedence. ๐ค==!=โ Boolean equal and not equal. ๐ฐeqneโ Boolean string equal and string not equal. ๐ฌinniโ List containment and negated list containment. The first argument is interpreted as a string, the second as a list.intests for membership in the list, andniis the inverse. ๐&โ Bit-wise AND. Valid for integer operands. ๐งฉ^โ Bit-wise exclusive OR. Valid for integer operands. โก|โ Bit-wise OR. Valid for integer operands. ๐ฏ&&โ Logical AND. If both operands are true, the result is1, or0otherwise. This operator evaluates lazily; it only evaluates its second operand if it must in order to determine its result. This operator evaluates lazily; it only evaluates its second operand if it must in order to determine its result. ๐||โ Logical OR. If both operands are false, the result is0, or1otherwise. This operator evaluates lazily; it only evaluates its second operand if it must in order to determine its result. ๐ฆx ? y : zโ If-then-else, as in C. Ifxis false, the result is the value ofy. Otherwise the result is the value ofz. This operator evaluates lazily; it evaluates only one ofyorz. ๐ญ
The exponentiation operator promotes types in the same way that the multiply and divide operators do, and the result is the same as the result of pow. Exponentiation groups right-to-left within a precedence level. Other binary operators group left-to-right. For example, the value of
expr {4*2 < 7}
is 0, while the value of
expr {2**3**2}
is 512. ๐คฏ
As in C, &&, ||, and ?: feature โlazy evaluationโ, which means operands are not evaluated if they aren't needed to determine the outcome. For example, in
expr {$v?[a]:[b]}
only one of [a] or [b] is evaluated, depending on the value of $v. This is not true of the normal Tcl parser, so it's normally recommended to enclose the arguments to expr in braces. Without braces, as in expr $v ? [a] : [b] both [a] and [b] are evaluated before expr is even called. ๐ญ
๐ For more details on the results produced by each operator, see the documentation for C.
๐ง MATH FUNCTIONS ๐ง
A mathematical function such as sin($x) gets replaced with a call to an ordinary Tcl command in the tcl::mathfunc namespace. The evaluation of an expression such as
expr {sin($x+$y)}
is the same in every way as the evaluation of
expr {[tcl::mathfunc::sin [expr {$x+$y}]]}
which in turn is the same as the evaluation of
tcl::mathfunc::sin [expr {$x+$y}]
Okay so when Tcl spots something like sin(...) inside an expression, it's not calling some secret built-in โ it's resolving a command name. ๐ซ And tcl::mathfunc::sin gets resolved exactly the way NAMESPACE RESOLUTION describes it in the namespace(n) docs. With the default value of namespace path, the two typical resolutions are [namespace current]::tcl::mathfunc::sin or ::tcl::mathfunc::sin. iykyk ๐
And just like in C, a mathematical function can accept multiple arguments separated by commas. So this:
expr {hypot($x,$y)}
becomes this:
tcl::mathfunc::hypot $x $y
Wanna know which math functions you get by default? Peep the mathfunc(n) docs bestie. ๐ซถ
โจ TYPES, OVERFLOW, AND PRECISION โจ
Internal floating-point computations are performed using the C double type. When you're converting a string to a floating-point value, exponent overflow gets detected and gives you the double value of Inf or -Inf as appropriate. Floating-point overflow and underflow get detected to the degree the hardware supports, which is generally pretty reliable. ๐
Converting between internal representations for integer, floating-point, and string operands? Automatic, whenever it's needed. ๐ For arithmetic computations, integers are used until some floating-point number gets introduced, and after that, floating-point values are used. Example:
expr {5 / 4}
returns 1, while
expr {5 / 4.0}
expr {5 / ( [string length "abcd"] + 0.0 )}
both return 1.25. And you can tell a floating-point result apart from an integer result by the presence of either โ.โ or โeโ:
expr {20.0/5.0}
returns 4.0, not 4. Not me being dramatic over a trailing zero, but it matters. ๐ญ
๐ฅ PERFORMANCE CONSIDERATIONS ๐ฅ
Okay bestie, listen up. ๐ When an expression contains syntax that Tcl would otherwise perform substitutions on, enclosing an expression in braces โ or otherwise quoting it so that it's a static value โ allows the Tcl compiler to generate bytecode for the expression. That means better speed and smaller storage requirements. It also avoids issues that can arise if Tcl is allowed to perform substitution on the value before expr gets called. Periodt.
In the following example, the value of the expression is 11, because the Tcl parser first substitutes $b, and then expr substitutes $a as part of evaluating the expression โ$a + 2*4โ. Enclosing the expression in braces would result in a syntax error, since $b does not evaluate to a numeric value.
set a 3
set b {$a + 2}
expr $b*4
๐จ Brace your expressions, or catch a syntax error. This is not a drill.
When an expression is generated at runtime, like the one above is, the bytecode compiler must ensure that new code gets generated each time the expression is evaluated. This is the most costly kind of expression from a performance perspective. ๐ In such cases, consider directly using the commands described in the mathfunc(n) or mathop(n) documentation instead of expr.
Most expressions aren't formed at runtime though โ they're literal strings, or they contain substitutions that don't introduce other substitutions. To allow the bytecode compiler to work with an expression as a string literal at compilation time, make sure it contains no substitutions, or that it's enclosed in braces or otherwise quoted to prevent Tcl from performing substitutions, letting expr perform them instead. โจ
If it's necessary to include a non-constant expression string within the wider context of an otherwise-constant expression, the most efficient technique is to put the varying part inside a recursive expr โ that at least allows for the compilation of the outer part, though it does mean the varying part must itself be evaluated as a separate expression. So in this example the result is 20, and the outer expression benefits from fully cached bytecode compilation. ๐ง
set a 3
set b {$a + 2}
expr {[expr $b] * 4}
In general, you should enclose your expression in braces wherever possible, and where that's not possible, the argument to expr should be an expression defined elsewhere as simply as possible. It's usually more efficient and safer to use other techniques (e.g., the commands in the tcl::mathop namespace) than it is to do complex expression generation. ๐ซถ
๐ธ EXAMPLES ๐ธ
A numeric comparison whose result is 1:
expr {"0x03" > "2"}
A string comparison whose result is 1:
expr {"0y" > "0x12"}
A forced string comparison whose result is 0:
expr {"0x03" gt "2"}
Define a procedure that computes an โinterestingโ mathematical function:
proc tcl::mathfunc::calc {x y} {
expr { ($x**2 - $y**2) / exp($x**2 + $y**2) }
}
Convert polar coordinates into cartesian coordinates:
# convert from ($radius,$angle)
set x [expr { $radius * cos($angle) }]
set y [expr { $radius * sin($angle) }]
Convert cartesian coordinates into polar coordinates:
# convert from ($x,$y)
set radius [expr { hypot($y, $x) }]
set angle [expr { atan2($y, $x) }]
Print a message describing the relationship of two string values to each other:
puts "a and b are [expr {$a eq $b ? {equal} : {different}}]"
Set a variable indicating whether an environment variable is defined and has value of true:
set isTrue [expr {
# Does the environment variable exist, and...
[info exists ::env(SOME_ENV_VAR)] &&
# ...does it contain a proper true value?
[string is true -strict $::env(SOME_ENV_VAR)]
}]
Generate a random integer in the range 0..99 inclusive:
set randNum [expr { int(100 * rand()) }]
๐ SEE ALSO ๐
array(n), for(n), if(n), mathfunc(n), mathop(n), namespace(n), proc(n), string(n), Tcl(n), while(n)
๐ KEYWORDS ๐
arithmetic, boolean, compare, expression, fuzzy comparison, integer value
๐ COPYRIGHT ๐
Copyright ยฉ 1993 The Regents of the University of California.
Copyright ยฉ 1994-2000 Sun Microsystems Incorporated.
Copyright ยฉ 2005 Kevin B. Kenny <kennykb@acm.org>. All rights reserved.
And that's a wrap, bestie โ this was the expr(n) page, straight outta Tcl 8.5. Go forth and brace your expressions. ๐ โจ๐ฆ
๐ฆ where this page comes from
- alpine 3.23: tcl9-doc 9.0.3-r0 ยท TCL
- alpine 3.24: tcl9-doc 9.0.3-r2 ยท TCL
- fedora 43: tcl-doc 1:9.0.2-1.fc43 ยท TCL AND GPL-3.0-or-later WITH Bison-exception-2.2 AND BSD-3-Clause
- fedora 44: tcl-doc 1:9.0.2-1.fc44 ยท TCL AND GPL-3.0-or-later WITH Bison-exception-2.2 AND BSD-3-Clause
- nixos 26.05: tcl 9.0.3
- Copyright (c) 1993 The Regents of the University of California
- Copyright (c) 1994-2000 Sun Microsystems, Inc
- Copyright (c) 2005 Kevin B. Kenny <kennykb@acm.org>. All rights reserved
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms