Version 10 of Math Operators as Commands

Updated 2007-01-13 16:14:51

AMG: This page discusses TIP 174 [L1 ], "Math Operators as Commands".

TIP 174 adds commands named +, -, ==, etc., for the purpose of exposing math operations to the script level without needing to go through [expr].


The following table lists all TIP 174 commands and defines their behavior by showing their expression equivalents. Parentheses are used to indicate associativity.

 Operation or test        Cmd       0      1        2       3 or more arguments

 Bitwise negation          ~      err     ~a      err                       err
 Logical negation          !      err     !a      err                       err
 Arithmetic negation       -      err     -a

 Sum                       +        0      a      a+b             ((a+b)+c)+...
 Product                   *        1      a      a*b             ((a*b)*c)*...
 Shift left                <<     err    err     a<<b                       err
 Exponentiation            **       1      a     a**b          a**(b**(c**...))

 Subtraction               -                      a-b             ((a-b)-c)-...
 Division                  /      err   1./a      a/b             ((a/b)/c)/...
 Remainder                 %      err    err      a%b                       err
 Arithmetic shift right    >>     err    err     a>>b                       err

 Bitwise and               &       -1      a      a&b             ((a&b)&c)&...
 Bitwise inclusive or      |        0      a      a|b             ((a|b)|c)|...
 Bitwise exclusive or      ^        0      a      a^b             ((a^b)^c)^...

 Numeric equality          ==       1      1     a==b       ((a==b)&(b==c))&...
 String equality           eq       1      1   a eq b   ((a eq b)&(b eq c))&...
 Numeric inequality        !=     err    err     a!=b                       err
 String inequality         ne     err    err   a ne b                       err

 List membership           in     err    err   a in b                       err
 List non-membership       ni     err    err   a ni b                       err

 Strict increasing order   <        1      1      a<b         ((a<b)&(b<c))&...
 Increasing order          <=       1      1     a<=b       ((a<=b)&(b<=c))&...
 Strict decreasing order   >        1      1      a>b         ((a>b)&(b>c))&...
 Decreasing order          >=       1      1     a>=b       ((a>=b)&(b>=c))&...

The - command is something of a changeling. In its unary form, it negates its first (and only) argument. For higher arity, it negates every argument except its first and returns the sum. While this may seem counterintuitive, it does match the behavior of the - expr operator.

Exponentiation (**) is right-associative.

Short-circuit logic (&&, ||) isn't supported because it cannot be implemented in Tcl. Tcl always eagerly determines the value of each argument before passing it to the command.

Shift right is arithmetic, not bitwise, meaning that the sign bit is unchanged by the operation. For two's-complement machines, arithmetic and bitwise shift left produce the same results.


AMG: When I first read the TIP, I wondered why the inequality operators were strictly binary. It seemed to me that they could be more general, that they could test to see if all elements of a list are distinct. In the zero- and one-argument cases, they would return true. In the two-argument case, they'd behave as expected. For three or more arguments, each possible argument pairing would be checked for inequality, e.g. (a!=b)&(a!=c)&(b!=c) for three arguments.

Today I asked the Tcl Chatroom, and the answer was that inequality operators are binary-only because the interpretation for other arities is not obvious; multiple reasonable interpretations exist.

  1. Pairwise inequality: (a!=b)&(b!=c)&(c!=d)
  2. Any inequality: (a!=b)|(a!=c)|(a!=d)|(b!=c)|(b!=d)|(c!=d)
  3. Total inequality: (a!=b)&(a!=c)&(a!=d)&(b!=c)&(b!=d)&(c!=d)

In the above table, every operator that does support three or more arguments (I'll call them ternary+ operators) has a commonly understood meaning when written a op b op c op d, for instance a == b == c == d. Never is a != b != c != d written because it would not be clear which of the above three interpretations is intended.

Moreover, for every ternary+ operator, interpretations (1) and (3) always yield the same result, assuming the list ordering isn't reversed when using areflexive operators. This is because they all exhibit transitivity: (((a op b) and (b op c)) implies (a op c)). Try it and see. :^)

RS pointed out that (2) is simply [! [== a b c d]]]. He also suggested a nice, simple implementation of (3) using [lsort]:

 proc distinct {args} {== [llength $args] [llength [lsort $args]]}

(Use the -real lsort option if you don't want "0", " 0", "0.0", "-0", etc. to be considered distinct.)

I can't imagine a single case where (1) is useful, but it wouldn't be difficult to implement.


LES I hope that TIP 174 never makes it to the core. That is all perfectly possible with sugar syntax. My position is: don't change the language except to implement something that is really not possible with the existing syntax and commands. If you want everything prêt-à-porter, make your own procs and classes and reuse them in every opportunity, or just code in PHP and its 1,000+ TV dinner functions.

AMG: Perhaps something similar to TIP 174 can be placed in tcllib to make it commonly available.

Lars H: You hope in vain, LES; TIP#174 is already (2007-01-13) part of the 8.5 core. An important reason for having it is that the commands already exist a bytecode operations, so its implementation was only about adding direct Tcl commands that compile to these things without taking the detour through the expr little language.


[ Category Mathematics | Category Language ]