expr

Difference between version 204 and 205 - Previous - Next
'''[http://www.tcl-lang.org/man/tcl/TclCmd/expr.htm%|%expr]''', a [Tcl Commands%|%built-in] [Tcl] command, evaluates an expression.



** See Also **

   [A little math language]:   Adds features & syntactic sugar to `expr`.

   [A real problem]:   

   [Arbitrary precision math procedures]:   

   [Brace your expr-essions]:   

   [compute]:   More syntactic sugar for `expr`.

   [Converting numbers from arbitrary bases]:   

   [DebuggingExprCalls]:   [rwm]: Sometimes it is difficult to debug `expr` calls where the operands are variables. [DebuggingExprCalls] explains how to wrap expr to help with these cases.

   [double substitution]:   

   `[cmdSplit%|%exprlex]` and `[cmdSplit%|%funclex]`:   Splits expressions and functions into their lexical components.

   `[ycl%|%ycl expr]`, by [PYK]:   A more concise version of `[expr]`.  Assigns the result to the given variable.  If no variable is provided, The `$expr` is used.

   [Floating-point formatting]:   Also explains how to format a floating point value without disturbing the [Tcl_Obj%|%disturbing the internal representation].

   [gotcha]:   `expr` figures prominently.

   [Tcl and octal numbers]:   The Octal Bug.

   [expr problems with int]:   Historical (pre-[Changes in Tcl/Tk 8.5%|%8.5]) information on the limits of number representation (both integer and float) inherited from [C].

   [for]:   

   [How can I do math in Tcl]:   

   [if]:   

   [Importing expr functions]:   An exploration into using `expr` functions without explictly calling `expr`.

   [infix]:   A package to facilitate writing sequences of mathematical formulae in the familiar infix form.

   [in] and [ni]:   `expr` operators to test for list membership.

   [Math function help]:   

   [Modeling COND with expr]:   Braced expressions can span several lines.

   [Numerical Analysis in Tcl]:   

   [Sample Math Programs]:   Extremely simple math examples.

   [Tcl help]:   

   [http://tip.tcl-lang.org/123%|%TIP #123]:   Adds exponentiation Operator to `expr`.

   [http://tip.tcl-lang.org/174%|%TIP #174]:   [Math Operators as Commands].

   [http://tip.tcl-lang.org/182%|%TIP #182]:   Adds the `bool` function.

   [http://tip.tcl-lang.org/201%|%TIP #201]:   Adds the 'in' and `ni` operators.

   [http://tip.tcl-lang.org/232%|%TIP #232]:   Adds the to add new functions at the script level. 

   [http://tip.tcl-lang.org/237%|%TIP #237]:   Adds arbitrary-precision integers.

   [while]:   




** Documentation **

   [http://www.tcl-lang.org/man/tcl/TclCmd/expr.htm%|%officieal reference]:   

   [tcl::mathfunc%|%mathfunc]:   

   [tcl::mathop%|%mathop man page]:   

   [tcl_precision]:   

   [http://www.tcl-lang.org/man/tcl/TclLib/GetInt.htm%|%Tcl_GetBoolean man page]:   



** Synopsis **

'''expr''' ''arg'' ?''arg arg ...''?



** Description **

`expr` [concat%|%concatentates] its arguments, evaluates this result as a Tcl 
expression, and returns the value of the expression.

`expr` implements a [little language] that has a syntax separate from [Tcl].
An expression is composed of values and operators.  Like Tcl, it interprets
[variable substitution], command substitution, double quotes and braces.
Unlike Tcl, it interprets anything that looks like a number as a number,
anything that looks like boolean as boolean, provides operators and functions,
and requires that literal string values be enclosed in double quotes or braces.

A value recognized as boolean by `[string is] boolean...` can be used directly,
without enclosing it in quotes or braces. 

The operators permitted in Tcl expressions include most of the operators
permitted in [C] expressions and a few additional ones.  The operators have the
same meaning and precedence as the corresponding [C] operators. Expressions canyielproduce numeric or non-numeric results.
FA functions takes the form,

    :   ''name''`(`''argument?'')
    
or
    :   ''name''`(`''argument''`,`''argument ...''`)`

The first character of ''name'' is a letter, and remaining characters areletters, digits or underscore. I.e. ''name'' matches the regular expression, 
'''`[[A-Za-z]][[A-Za-z0-9_]]*`''' .  Each ''argument'' is itself a complete
expression. 
Each ''argument'' to a function is itself a Tcomplete expression.  For example:

======
cos($x+$y)
======



** Usage **

======
set val1 8.2
set val2 6
expr {$val1 + $val2}
======

Result:

======
14.2
======

In most cases, it's best to [Brace your Expr-essions%|%brace] or otherwise
escape the argument to `[expr]`.  In particular, the special Tcl characters,
`$`, `[`, `"`, `{` should normally be escaped:

======
expr {$val1+$val2}
======
This allows `expr` eventos dTcl from thpe rforming [substerpreitaution, ra%|%substher than having Tcl interpreut
them fironst] aond the
arguments, hleaving it to `expr` to interpret them agas int will.  See below for 
more
 details.

`expr` expressions differ from [C] expressions in the way that operands are
specified.  They also include some non-numeric operators for strings
(comparison) and lists (membership).



** Operators **
Since Tcl [Changes in Tcl/Tk 8.5%|%8.5], many operators have command- equivalents in the
'''::[tcl::mathop]''' [namespace].
In spite of the name '''mathop''', some of the operators are string-oriented, rather
than math-oriented.
The following is a chart of operators, in order of precedence (tightest-binding
to least-tight associativity):
&| [-] [+] [~] [!] | Unary operators; specifically a negation opveration, a npon-negatsion operationve, a bit-wise NOT operation (every bit in the input value gets replaced by its inverse), and a logical NOT operation (non-zero maps to zero, and zero maps to one). |&
&| [**] | eExponential power. From Tcl [Changes in Tcl/Tk 8.5%|%8.5] on. |&
&| [*] [/] [%] | Multiplication, division and ''integer'' remainder. (s See `fmod()` below.) |&
&| [+] [-] | Addition and subtraction. |&&| [<<] [>>] | Left and right shift.  Equivalent to multiplying or dividing by a suitable power of two, and then reducing the result to the range representhat can ble instored as an integer on the host platform. |&
&| [<] [>] [<=] [>=] | OrdLering relations:  less than, greater than, less -than or equal, and greater -than or equal.  These oOperationds workmaybe onbe stnumeringsc asor well as non-numbersic, but where string comparison is intended, it is advisable to use the dedicated string comparison operators, or [string compare] or [string equal] instead,  as those are  more predictable in the case of a string that looks like a number.  For example, [string equal] considers "6" and "06" to be different strings, but the `expr`' operator `==` considers them to be numeically equivalent numbers.|&
&| [==] [!=] | Equality and inequality.   These oOperationds workmay onbe stnumeringsc asor well as non-numbersic, but seefor thnon-numeric descompariptisons `equality`, op`nerators`, for no`[string esqual]` are bouet stering chompariceson. |&
&| [eq] [ne] | Strinceg Tcequality [Changesd in Tcequal/Tk 8ity.4%|%8.4], these are string-cFomparison operxators.mple, "`6"` and "`06"`, asre wnot equall, asn neither are `1` and `1.0,`. will compaIntroduced uinequ [Changes in Tcl/Tk 8.4%|%8.4]. |&
&| [in] [ni] | chPrecksence forand occurrabsence of an istemring in a list. New in Tcl [Changes in Tcl/Tk 8.5%|%8.5]. |&
&| [&] | Bit-wise AND.  A bit is set in the result when the corresponding bit is set in both thope argumeantds. |&
&| [^] | Bit-wise exclusive OR.  A bit is set in the result when the corresponding bit is set in ''precisely one'' of the argumoperantds. |&
&| [<<pipe>>] | Bit-wise OR.   A bit is set in the result when the corresponding bit is set in either of the argumoperantds. |&
&| [&&] | Logical AND.   The result is `1` when both of the argumoperantds are true. and `0` otherwise.  This operation is a ''short-circuiting'' operation,: and willIt only evaluates its second argumoperantd when the first argument is non-zetroue.  ThisIf includes the expansiecond of Tcl commperands in squarppe brackets.  Where Tcl seems not to be behaving as luated whescrn ibet shouldn't bere, see [double substitution]. |&
&| [<<pipe>><<pipe>>] | Logical OR.  The result is `0` when both of thpe argumeantds are false, and `1` otherwise.  This operation is a ''short-circuiting'' operation,: and willIt only evaluates its second argumoperantd when the first argument is zero.  Whern the Tseclond soperand appemars not to be behaving as luated whescrn ibet shoudn't bere, see [double substitution]. |&
&| ''x'' '''?''' ''y'' ''':''' ''z'' | If-then-else, as in [C]. `x`, `y`, and `z` are expressions.  The result is `y` if `x` is true, and `z` otherwise.  This operation is a ''short-circuiting'' operation:  If `x` is true, `z` wills not be evaluated, and if `x` is false, `y` wills not be evaluated.  WhIf an opereand Tcl sappeemars not to be behaving as luated whescrn ibet shouldn't bere, see [double substitution].  `[if]` performis just as wpell rfomas nthis construinct.e  Tthe generated bytecode is identical. |&


It would have been better for the bitwise operators to have a higher precedence
than the equality operators.  The current precedence is inherited from [C],
which, for idomatic compatiblity with `B`, gave them a lower precedence.



** Functions **

See the [http://www.tcl-lang.org/man/tcl/TclCmd/mathfunc.htm%|%mathfunc man page].

The following is a list of builtin functions:

   '''[abs]'''(x):   Absolute value (negate if negative).

   '''[acos]'''(x):   Inverse cosine (result in radians).

   '''[asin]'''(x):   Inverse sine (result in radians).

   '''[atan]'''(x):   Inverse tangent (result in radians).
   '''[atan2]'''(y,x):   Inverse tangent.  Can handle cases which plain `atan()` can't (due to division by zero), and has a larger output range. ( The result in radians).
   '''[bool]'''(x):   Accepts any valid boolean value and pretodurnces the corresponding boolean valumber `0` or `1`.
   '''[ceil]'''(x):   Ceiling. (d Defined over floating point numbers.)  If the input value is not a whole number, pretodurnces the next ''larger'' whole number. '''Surprise''': The Pretodurn valuce is a float, not an integer.
   '''[cos]'''(x):   Cosine. (input ''x'' ins a radians) value.

   '''[cosh function%|%cosh]'''(x):   Hyperbolic cosine.
   '''[double]'''(x):   ConvePrt nodumbcers tohe floating point representation of a number.
   '''[entier]'''(x):   Like `int(x)`, but there is no limit ton the sinputze orf output value''x''.
   '''[exp]'''(x):   Exponential function.  RetuPrnoduces ''e'' to the power of `x`, where ''e'' is the base of natural logarithms.
   '''[floor]'''(x):   Floor. (d Defined over floating-point numbers.)  If the input value is not a whole number, pretodurnces the next ''smaller'' whole number as a floating-point number.

   '''[fmod]'''(x, y):   Floating-point remainder of x divided by y.

   '''[hypot]'''(x,y):   Hypotenuse calculator.  Assumes boring old Euclidean geometry.  If the projection of a straight line segment onto the X axis is `x` units long, and the projection of that line segment onto the Y axis is `y` units long, then the line segment is `hypot(x,y)` units long. Equivalent to `sqrt(x*x+y*y)`.

   '''[int]'''(x):   Convert number to integer by truncation.  Limited by the size of long in [C].

   '''[isqrt]'''(x):   Compute the integer part of the square root of `x`.

   '''[log]'''(x):   Natural logarithm.

   '''[log10]'''(x):   Logarithm with respect to base 10.

   '''[max]'''(x,...):   The argument with the greatest value.

   '''[min]'''(x,...):   The argument with the least value.

   '''[pow]'''(x,y):   Power function.  `x` to the power of `y`.
   '''[rand]'''():   Random number.  Uses uniform distribution over the range [0,1).  ''This R'NG is not suitable for cryptography.ic purposes'''.
   '''[round]'''(x):   Round to nearest whole number.  '''Not suitable for financial rounding.'''.
   '''[sin]'''(x):   Sine. (input ''x'' ins a radians) value.

   '''[sinh]'''(x):   Hyperbolic sine.
   '''[sqrt]'''(x):   SquaProduces rootas (wa reall, thnumber positivhe square root only.f  And Tcl doesn't do complhex math, spo sithive input had mbetter be positive)''x''.
   '''[srand]'''(x):   Seeds the random number generator with the given valuteger ''x''.  Each interpreter has its own random number generator, which starts out seeded with the current time.
   '''[tan]'''(x):   Tangent. (input ''x'' ins radians value.)
   '''[tanh]'''(x):   Hyperbolic tangent.kjh
   '''[wide]'''(x):   Take any numePric valoduce,s and return the low order 64 bits of the integer value of the argumbentr ''x''.



** Mathematical Expressions **


Simple addition:

======
set a [expr {1 + 2}]
======

mathematical functions

======
set a [expr {sqrt(4)}]
======
[martin Lemburg]: The following returns `1` because `" 2 "` wills be interpreted
as `2`:

======
set a [expr {" 2 " == [string trim " 2 "]}]
======
To ensure that exopreratorssi chonose reval nuatmbesr to eva flouating point number, use `double()`
or `floor()` to produce the numeric real representation of at least one argument:

======
set a 1
set b 2
expr {double($a)/$b}
======

or, to get an integer:

======
expr {entier($a/$b)}
======

`int()` would also have worked, but `entier()` is more general


** Order of Precedence **

The following returns returns 4, rather than -4 as some might expect:

======
set a [expr {-2**2}]
======

The following returns `1` because `2==2` is evaluated first:

======
set a [expr {5&2==2}]
======

[AMG]: The order of bitwise operations (`|`, `&`, and `^`) may seem totally bogus, but it's inherited from [C], which in turn inherited it from an early prototype version of C which lacked separate logical operators (`&&` and `||`) [http://cm.bell-labs.com/who/dmr/chist.html]. I wouldn't cry if a new language (not Tcl) decided to break compatibility with C in this respect.


** Composing Expressions **
`expr` tries to interpret operands as numeric values, but doesn't reparse 
variable valsuebstitutions as expressions, so, afor vexamplue, `2*3`
is interpreted as a string:

======
set y 2*3; expr {$y}   ;# ==> 2*3
set y 2*3; expr {$y+2} ;# ==> can't use non-numeric string as operand of "+"
======

To pass a complete expression stored in a variable, omit the braces so that Tcl
[double substitution%|%substitutes the variable] before passing it to `expr` :

======
set y 2*3; expr $y ;#  ==> 6 
set y 2*3; puts [expr $y+2] ;# ==> 8
======

But be careful not to introduce an [injection attack] vulnerability.  See
[double substitution].



** Literal String Operands **
`expr` implements a [little language] distinct from Tcl ithse languagef, which is described in [dodekalogue%|%the rules of Tcl].  One
difference is that `expr` requires literal strings to be quotescaped:

======none
%  if {joe eq mike} {puts wow}
syntax error in expression "joe eq mike": variable references require preceding $
%  if {"joe" eq "mike"} {puts wow}
%  if {{joe} eq {mike}} {puts wow}
======

To insert a literal value when templating an expression, use an [identity
function] like `[lindex]`:

======
set expr {[lindex @val1@] eq [lindex @val2@]}
set expr [string map [list @val@ [list $var1] @val2@ [list $var2]] $expr]
expr $expr
======


** Canonical Representation of a Number Form **
If the return value of `expr` is numeprioduc,es ithe decis trmansfl of a rmed sultintog va canonical
numeric form:

======
set val 0x10
puts $val ;# 0x10
set val [expr {$val}]
puts $val ;# 16
======

======
puts [expr {[join {0 x 1 0} {}]}] ;# 16
======
It may be [gotcha%|%surprising] to find that even when no operators are
present, the string that  `expr` may not be the string that was passed to it.
In other words, `expr` may mutate strings that can be interpreted as
numbers, which is a potential [gotcha] when using string functionality
of `expr` while not considering that they may have a numeric
interpretation.


** A Logical Conundrum **

Consider the following example:

======
% expr {1 == true}
0
% expr {1 == !!true}
1
======

The logical operators assign numeric interpretations to various values,
including `true` and `false`.  The `==` operator itself is not a logicaloperator, and although it inteprets each value as numeric if possible, it has a
more limite
d concept of what constitutes a numeric value, and it does not
 consider values like `true` or `false` to be numeric, as a logical
operator would.  In the first expression,
 "true" is interpreted as a string, 
but because of a quirk in the implementation
 of Tcl, unlike other string
values, it is not required tohat it be quoted, as other string values are. 



** The Octal Bug **

See [Tcl and Octal Numbers] for details.

[rjm]: Why does `expr` return integers with leading zeroes as hex?, e.g.

======
expr 0100 ;# -> 64
======

[AMG]: The leading zero makes 0100 octal.  The 1 is in the 64's place, hence
the result is 64 in decimal.  That's not hexadecimal.  `expr` always
returns a decimal value; you have to use `[format]` if you want it in some
other base.

[RJM]: I came around this as I was going to do calculus on a four-digit
formatted number in an entry field. I had to apply `scan $var %d` to get rid
of the leading zeroes - as would be '''explicitly''' necessary in every typed
language...



** Floating-Point Arithmetic **

`expr` uses floating point arithmetic, so strings representing decimal
fractions that don't have a precise floating-point representation will be given
to a close-enough representation.  In the following example, `36.37` gets a
floating-point representation that approaches 36.37: 

======
expr {int(36.37*100)}
======

If that value is subsequently used as a string, it becomes necessary to somehowcpronvducer its string representation.  Over the years, the standefaultrd string conv
representation has varied.  For Tcl
 version 8.5.13, it looks like

======none
3636.9999999999995
======

[RS] points out that version 8.4.9 provided the following results, and that
that braced or not, `expr` returns the same (string rep of) double as well
as integer, so the issue of bracing one's expressions is not relevant to the
issue of floating-point to string conversion.

======none
% expr 36.37*100
3637.0 ;#-- good enough...
% expr {36.37*100}
3637.0 ;#-- the same
% expr {int(36.37*100)}
3636   ;#-- Hmm
% expr int(36.37*100)
3636   ;#-- the same
% info pa
8.4.9
======

One way to get `3637` would be to use `round()`:

======
expr {round(36.37*100)}
======

`[format]` can also be useful, but the main point is to remain
aware of the context and decide if and how to use floating-point operations.

[LV]:  My response on [comp.lang.tcl] was that I thought it was a shame
that `expr` (or perhaps it is Tcl) didn't use the same mechanism for
both calculations of 36.37 * 100 ; that way, the results would at least
be consistent.  Even if they were consistently '''wrong''', one would
be able to at least to live within the ''law of least surprise''.
As it is, until one experiments, one won't know which way that Tcl
is going to ''round'' results.

[EPSJ]:  This may be a side effect of the IEEE floating point standard. This is
done in hardware to guarantee the convergence in the case of a series of math
algorithms. The rule is that the mantissa of a floating point number must be
rounded to the nearest even number. As 36.37 cannot be represented exactly in
float point it ends up being a small fraction below the intended number. On the
other side 36.38 moves on the other direction. Look the following result:

======none
() 60 % expr int(36.380*100)
3638
() 61 % expr int(36.370*100)
3636
======

x86 floating point hardware allows this to be configurable to nearest even,
nearest odd, and a few more options. But usually nearest even is the default.
The result may seem inconsistent, but it is intentional.


** pow() vs **

[LES] 2005-07-23:

======none
% expr pow(5,6)
15625.0

% expr 5**6
15625
======

Two syntaxes, two slightly different results. Is that intentional?

[RS]: Yes.  While `pow()` always goes for double logarithms, `**` tries to do
integer exponentiation where possible.



** String Representation of Floating Point Numbers **


The reason that Tcl's float->string and string->float are so very complicated
is the combination of (a) 1/2 ulp accuracy through the entire numeric range;
(b) lossless conversion (float->string->float always recovers the original
number), (c) speed.  That's what balloons the conversion from the eight or ten
lines that you'll see in an elementary text to a few thousand lines of code,
moslly working in bigints.


See [kbk], [Tcl Chatroom], 2018-11-28




** Precision **

[davou]: What is the precision of functions in `expr`, and how can it be
expanded upon?

[Lars H]: That's generally determined by the [C] library functions that
implement them. It depends on where (and against what) Tcl is compiled.  For
real numbers, that means '''double'''s, which are floating-point numbers of
typically about 17 decimal digits precision (but how many of these are correct
varies between functions and platforms). For integers Tcl has traditionally
used '''long'''s, which in most cases means 32-bit two's complement integers
(`$tcl_platform(wordSize)` tells you the actual number of bytes), but as of Tcl
[Changes in Tcl/Tk 8.5%|%8.5], it supports (almost) arbitrarily large integers ([googol magnitude] is no
problem anymore, whereas googolplex magnitude wouldn't fit in the computer
memory anyway). As for extending what the core provides, [tcllib] provides
[math::bignum] and [math::bigfloat].



** [Nan] and [Inf] **


At least as of Tcl [Changes in Tcl/Tk 8.5%|%8.5], [NaN] and [Inf] are potential values returning from
`expr`.

[Philip Smolen] I've never seen expr return NaN.  I wish it would!

======
[phil@harvey ~]$ tclsh8.6 
% expr sqrt(-1)
domain error: argument not in valid range
% ::tcl::mathfunc::sqrt -1
-NaN
% info patchlevel
8.6.4
% expr {Inf+1}
Inf
% 
======


======
[phil@becca ~]$ tclsh8.5 
% expr sqrt(-1)
domain error: argument not in valid range
% ::tcl::mathfunc::sqrt -1
-NaN
% info patchlevel
8.5.14
% expr {Inf+1}
Inf
% 
======


** Interactions with `[locale]` **

pParsing of decimals in `expr` may be hampered by `[locale]` - you might get
''syntax error in expression 1.0''



** [Brace your expr-essions%|%Brace Your Expressions%|%] For Syntax **

`expr` concatenates its arguments into an expression.  Consider the following
error:

======
expr 5 > {} ;# -> missing operand at _@_
======

The problem in the example above is that `expr` concatentates the arguments
into the expression, `5 >`, which is incomplete.  Here is another example in
which arguments are concatenated, and don't form a correct expression:

======
set color1 green
set color2 green

#wrong
expr $color1 eq $color2 ;# -> invalid bareword "green"
======

Concatenated, the arguments form the script, `green eq green`, in which the two
values are unquoted, which is a syntax error.  The following commands both
result in correct expressions: 

======
expr {$color eq $color2} ;# -> 1
expr {$color1} eq {$color2} ;# -> 1
======

But if the arguments are not bracketed, there's a syntax error:

Another example illustrating the same point:

======
set a abc
set b [list 123 abcd xyz lmnop]
expr $a in $b
# invalid bareword "abc"
# in expression "abc in 123 abcd xyz lmnop";
# should be "$abc" or "{abc}" or "abc(...)" or ...

expr {$a in $b} ;#-> 0

expr {$a ni $b} ;#-> 1
======

======
% expr $a eq "foo" ? true : false
invalid bareword "abc"
% expr {$a eq "foo" ? true : false}
false
======


** [Brace your expr-essions%|%Brace Your Expressions%|%] for Performance **

When exactly one unconcatenated value is passed to `expr`, the argument can be
compiled to [bytecode], which is much more efficient.  "Unconcatenated" means
that the argument must not contain multiple substitutions or be the
concatenation of substitutions and literal text.  The goal is for there
to be a persistent [Tcl_Obj] in which to store the compiled math expression.
If `expr` has to concatenate its arguments (i.e. it is passed more than one
argument), or if [Tcl] has to concatenate the results of multiple substitutions
and literal substrings, then the math expression will be in a temporary Tcl_Obj
which must be regenerated every time `expr` is called.

'''Fast:'''

======
expr {2 + 2}         ; # Preferred
expr 2+2             ; # Valid but lazy (1)
expr "2 + 2"         ; # Valid but not preferred (2)
expr 2\ +\ 2         ; # Valid but ugly (3)
expr $expression     ; # Valid
expr [expression]    ; # Valid
======

(1) This style is easy to type and is fine for interactive use, but you will lose performance (and correctness and security) if you use this notation in combination with variable and script substitutions.

(2) Same problems as (1).  Use braces instead.

(3) Same problems as (1), plus you might forget a backslash before a space, thereby forcing `expr` to concatenate its arguments.

'''Slow:'''

======
expr 2 + 2           ; # Slow since [expr] must concatenate its arguments
expr 2 + $x          ; # Slow since [expr] must concatenate its arguments, also unsafe
expr 2+$x            ; # Slow since Tcl must concatenate to determine argument, also unsafe
expr "2 + $x"        ; # Slow since Tcl must concatenate to determine argument, also unsafe
======



** [Brace your expr-essions%|%Brace Your Expressions%|%] for Security **

[AMG]: The security problems of unbraced `expr`essions are very similar to
[SQL] [injection attack%|%injection attacks].  Notice how [sqlite]'s [Tcl] binding does its own
variable expansion to avoid this very problem.  Many, many [sh] scripts have
this problem as well because the default is to apply multiple passes of
interpretation.

See also [double substitution].



** Remember `[if]`, `[for]`, and `[while]` **

[AMG]: The above speed and security concerns also apply to `[if]`,
`[for]`, and `[while]` since they share the expression engine with
`expr`.

Additionally, `[for]` and `[while]` really do need their expressions to
be braced.  In order for the loop to execute a nonzero but finite number of
times, the expression's value must not be constant; but if they're not braced,
their value is determined before the loop can begin.

The exception is when the ''expression'' (as opposed to value) is contained in
a variable, in which case it must not be brace-quoted, or else the command
would try to treat the expression as a (string) value and almost certainly fail
to convert it to a boolean value.

[DKF]: But even then, for `if`, `for` and `while` you must still brace the expression to avoid being stuck in the compilation slow lane. Putting an `expr` inside can help:
======
set ex {$f > 42}
while {[expr $ex]} {
    puts "This is the body: f is now [incr f -1]"
}
======

----

Consider what would happen if this script were actually working with user
input:

======
#DON'T EXECUTE THIS SCRIPT!!!
set x {[exec format C:\\]}
set j {[puts Sucker!]}
#C:\ get formatted in the next command
set k [expr $x / $j.]
======

On the other hand,

======
set k [expr { $x / double($j) }]
======

gives a much more reasonable result:

======none
argument to math function didn't have numeric value
   while executing
"expr { $x / double($y) }"
   invoked from within
"set k [expr { $x / double($y) }]
"
    (file "foo.tcl" line 3)

======



** Concise Assignment **

`expr` is usually used to assign a result to a variable:

======
set m [expr {0.5 * $width * $radius}]
======

A small procedure makes it possible to write this instead:

======
= m {0.5 * $width * $radius}
======

here is the procedure:


======
proc = {name args} {
    ::tailcall try "::set [list $name] \[::expr $args]"
}
======




** The 'Dot' Trick for Unbraced Expressions **

Unless you know exactly what you are doing, unbraced expressions are not
recommended.  Nevertheles...

With unbraced expressions, `.` (`\x2e`) can be appended to a variable to get `expr`
to interpret the value as a float, but `double()` is a better alternative:

======
set x 1; set j 2

# works (but don't do this)
expr $x/$j.

#an accepted way to do it
expr {double($x)/$j}

# error: syntax error in expression "$x/$j."  (expr parser)
expr {$x/$j.}
======

It's faster, too:

======
set script1 {
   set x 1
   set j 2
   set k [expr $x / $j.]
}
set script2 {
   set x 1
   set j 2
   set k [expr { $x / double($j) }]
}
foreach v {script1 script2} {
   puts "$v: [time [set $v] 10000]"
}

#script1: 38 microseconds per iteration
#script2: 9 microseconds per iteration

#[pyk] 2012-11-28: what a difference a few years makes (an "old" 3.06Ghz Intel Core 2 Duo):
#script1: 4.4767364 microseconds per iteration
#script2: 0.7374299 microseconds per iteration
======

----

[RS]: This was just to demonstrate the differences between the regular Tcl
parser and the parser for `expr`', not recommended practice. Another example is
substitution of operators:

======
set op +
expr 4 $op 5
9
expr {4 $op 5}
syntax error in expression "4 $op 5"
======

See the `[for]` page on a case where that helped.

** Bytecode compilation and performance **

[AMG]: When expr's argument is properly braced, the expression can be bytecoded for significant performance gains. However, the performance is not always quite as good as one would hope. Use [tcl::unsupported::disassemble] to see this in action:

======none
% tcl::unsupported::disassemble script {expr {4 / 3. * acos(-1) * $r ** 3}}
ByteCode 0x00000000025FADB0, refCt 1, epoch 16, interp 0x00000000026365B0 (epoch 16)
  Source "expr {4 / 3. * acos(-1) * $r ** 3}"
  Cmds 1, src 34, inst 17, litObjs 5, aux 0, stkDepth 3, code/src 0.00
  Commands 1:
      1: pc 0-15, src 0-33
  Command 1: "expr {4 / 3. * acos(-1) * $r ** 3}"
    (0) push1 0         # "1.3333333333333333"
    (2) push1 1         # "tcl::mathfunc::acos"
    (4) push1 2         # "-1"
    (6) invokeStk1 2 
    (8) mult 
    (9) push1 3         # "r"
    (11) loadStk 
    (12) push1 4         # "3"
    (14) expon 
    (15) mult 
    (16) done 
======

This shows that `4 / 3.` is precomputed to `1.3333333333333333`, but `acos(-1)` is not precomputed to `3.141592653589793`. While it would seem ideal to fold the constants together into `4.1887902047863905`, doing so would skip invoking `[tcl::mathfunc]::[acos]`, which might have a `[trace]` on it. Tcl optimizations always favor correctness over speed, so this shortcut is not available.

Here's the above again, but with local variables which provide a large speed boost by avoiding looking up the variable by name:

======none
% tcl::unsupported::disassemble lambda {{} {expr {4 / 3. * acos(-1) * $r ** 3}}}
ByteCode 0x00000000027A1080, refCt 1, epoch 16, interp 0x00000000026E65B0 (epoch 16)
  Source "expr {4 / 3. * acos(-1) * $r ** 3}"
  Cmds 1, src 34, inst 16, litObjs 4, aux 0, stkDepth 3, code/src 0.00
  Proc 0x00000000026A8620, refCt 1, args 0, compiled locals 1
      slot 0, scalar, "r"
  Commands 1:
      1: pc 0-14, src 0-33
  Command 1: "expr {4 / 3. * acos(-1) * $r ** 3}"
    (0) push1 0         # "1.3333333333333333"
    (2) push1 1         # "tcl::mathfunc::acos"
    (4) push1 2         # "-1"
    (6) invokeStk1 2 
    (8) mult 
    (9) loadScalar1 %v0         # var "r"
    (11) push1 3         # "3"
    (13) expon 
    (14) mult 
    (15) done 
======

(For disassembly readouts, it's not necessary to list the variables as arguments to the lambda. They'll be assigned slots in the compiled locals table either way. You're not actually running the code, so it doesn't matter if the variable exists.)

Common subexpressions cannot be optimized because this would bypass some potential traces on variable access and procedure invocation. If `expr` could know in advance that particular procedures and variables don't have traces, it would have greater freedom to perform common subexpression elimination. Knowing that a procedure is a pure function (its result depends only on its arguments), plus knowing that its definition will not change throughout the execution of the program, would let expr treat `acos(-1)` as a constant.

Now rearrange the expression to put the division at the end. Algebraically, this should produce an identical result. But because of potential floating point precision issues (non-commutativity of operations), Tcl must play it safe and do the operations in the order specified:

======none
% tcl::unsupported::disassemble script {expr {4 * acos(-1) * $r ** 3 / 3.}}
ByteCode 0x00000000025F91B0, refCt 1, epoch 16, interp 0x00000000026365B0 (epoch 16)
  Source "expr {4 * acos(-1) * $r ** 3 / 3.}"
  Cmds 1, src 34, inst 20, litObjs 6, aux 0, stkDepth 3, code/src 0.00
  Commands 1:
      1: pc 0-18, src 0-33
  Command 1: "expr {4 * acos(-1) * $r ** 3 / 3.}"
    (0) push1 0         # "4"
    (2) push1 1         # "tcl::mathfunc::acos"
    (4) push1 2         # "-1"
    (6) invokeStk1 2 
    (8) mult 
    (9) push1 3         # "r"
    (11) loadStk 
    (12) push1 4         # "3"
    (14) expon 
    (15) mult 
    (16) push1 5         # "3."
    (18) div 
    (19) done 
======

Back to common subexpression elimination: It may seem that the solution is for the programmer to manually precompute common subexpressions and reference their values via variables. This generally helps, so long as the subexpressions aren't too simple, but you must use local variables or else performance will suffer:

======
% proc a {x} {expr {cos($x * acos(-1)) + sin($x * acos(-1))}}
% proc b {x} {set y [expr {$x * acos(-1)}]; expr {cos($y) + sin($y)}}
% proc c {x} {set ::y [expr {$x * acos(-1)}]; expr {cos($::y) + sin($::y)}}
% set x 12.3
% time {a $x} 1000000
1.536581 microseconds per iteration
% time {b $x} 1000000
1.333106 microseconds per iteration
% time {c $x} 1000000
1.994305 microseconds per iteration
======



** History **


In [http://groups.google.com/group/comp.lang.tcl/browse_thread/thread/f873d6fab9f0e304%|%Embedded vs. separate commands], 1992-12-38, [JO] published the voting results 37:8 in favor of embedded functions() vs. separate [[commands]]


** (Tcl [Changes in Tcl/Tk 8.4%|%8.4] and older) 32-bit integer limitations **

Addition

======none
% expr (1<<31)-1
2147483647

% expr 2147483647 + 2147483647
-2
======

Multiplication

======none
% expr sqrt((1<<31)-1)
46340.9500011

expr 46341*46341
-2147479015
======

These are results of Tcl [Changes in Tcl/Tk 8.4%|%8.4] and older versions using a 32-bit representation
for integers.

Tcl [Changes in Tcl/Tk 8.5%|%8.5] features abritrary-precision integers.  See
[http://www.tcl-lang.org/cgi-bin/tct/tip/237.html%|%TIP #237].



** Suggestion to Reparse `expr` Variables **

[RS] suggests that arguments to `expr` could be reparsed so that full mathematical
expressions in variable values would interpreted as such

[RS] 2003-04-24: Here's a tiny wrapper for friends of infix assignment:

======none
proc let {var = args} {
    uplevel 1 set $var \[expr $args\]
} ;#RS
======

======none
% let i = 1
1
% let j = $i + 1
2
% let k = {$i + $j}
3
======

======
set y 2*3; puts [expr $y+0] ;# ==> 6
======

[AM]: The problem with variables whose values are actually expressions is that
they change the whole expression in which they are used. The performance gain
for caching the parsed expression will then be lost.

[AMG]: This reopens the door to all the security, performance, and correctness problems solved by bracing one's expressions.
** Unsuitability of expr for time offset calculations **

[Wookie]:  I had some trouble recently using `expr` to calculate time
offsets. I had 2 time stamps in the form hh:mm

So I had 4 variables h1, m1, h2, m2 and one of my `expr` functions was

======
set result [expr {$m1 + $m2}]
======

As many of you may be thinking, you fool! what about 08 and 09, which will get
treated as invalid octal. So after some grumbling I thought okay so I have to
trimleft them. Bit verbose but who cares:

======
set m1 [string trimleft $m1 0]
set m2 [string trimleft $m2 0]
set result [expr ($m1 + $m2)]
======

Now what could possibly go wrong with that... well obviously 00 becomes the
empty string, which causes unexpected closed parameter in the `expr`ession.
So now I have to check for the empty string. So...

======
set m1 [string trimleft $m1 0]
if {$m1=={}} {set m1 0}

set m2 [string trimleft $m2 0]
if {$m2=={}} {set m2 0}

set result [expr {$m1 + $m2}]
======

... and then repeat it for the hours. It all seemed very clumsy. So I came up
with this, which may solve many of the conversion issues in this section.

======
scan "$h1:$m1 $h2:$m2" "%d:%d %d:%d" h1 m1 h2 m2
set result [expr {$m1 + $m2}]
======

All the conversions to int have been done and leading 0's have been stripped
and returns 0 if the value is all 0s. This works for float and probably double
(though I've not tried). Can anyone see any problems with this approach?

[glennj]: No, `[scan]` is definitely the way to parse numbers out of dates
and times.  However, for date arithmetic, nothing beats `[clock]`.

======
# adding a delta to a time
set h1 12; set m1 45
set h2 3; set m2 30
clock format [clock add [clock scan "$h1:$m1" -format "%H:%M"] $h2 hours $m2 minutes] -format %T ;# ==> 16:15:00
======

What are you trying to do with your two times?



** Page Authors **

   [AMG]:   

   [PYK]:   

<<categories>> Arts and crafts of Tcl-Tk programming | Tcl syntax | Command | Mathematics | Tcl'''[http://www.tcl-lang.org/man/tcl/TclCmd/expr.htm%|%expr]''', a [Tcl Commands%|%built-in] [Tcl] command, evaluates an expression.