Tcl needs to have a better way to evaluate math than the expr command. It makes any code that has a modest amount of math difficult to write and difficult to read. I think that changing the interpreter to interpret single quoted expressions as math could be an elegant solution to this age-old problem and could make Tcl a more attractive option for people.
Here is a simple proof of concept:
proc betterTcl {body} { uplevel 1 [regsub -all {'((?:[^'\\]|\\.)*)'} $body {[expr {\1}]}] } betterTcl { set x 1.0 set y '$x*10' set z '$x + $y' set myList [list '$x+1' '$y - 5'] } puts $x; # 1.0 puts $y; # 10.0 puts $z; # 11.0 puts $myList; # 2.0 5.0
-AMB
NR - 2025-06-03 22:21:56
What would be nice is to do away with the $.
AMB - 2025-06-04 16:53:46
After trying to modify the parser a bit, I think it might actually be better to use parentheses to delineate expressions.
Here's a really simple proof of concept with some regex (without any nesting)
proc betterTcl {body} { uplevel 1 [regsub -all {\([^)(]*\)} $body {[expr {\0}]}] } betterTcl { set x 1.0 set y ($x*10) set z ($x + $y) set myList [list ($x+1) ($y - 5)] } puts $x; # 1.0 puts $y; # 10.0 puts $z; # 11.0 puts $myList; # 2.0 5.0
I think it looks nice, and doesn't introduce any new delimiters to Tcl. The parentheses would act like curly braces, but would then pass the resulting string to be parsed by the expr language. Someone is proposing something similar, to use $(expr) to denote expressions (see TIP 672 ), but this breaks code that uses the null array {} to store data, such as stooop, and frankly is confusing to me because the $ is for variable substitution, not for math.
I am going to try to implement this and submit it as a TIP.
KSA This proposal breaks code as well. For example:
regexp (123|456) "There are 123 ways to do things in Tcl"
Creates many problems just to save a few keystrokes. Is it worth the price? Even if they can be solved: I can't imagine many people will use it. Most people (at least I do) code for compatibility across language versions: expr does work in every version of Tcl but "(...)" does not.
PS: Speaking of expr: The thing that forces me regularily to switch to a different language (mostly GNU Octave or Python) is the lack of list/vector arithmetics, e.g. something like this:
% This does not work unfortunately to compute the median absolute deviation of a data series... set x {4.2 2.4 3.1 2.8 9.3} set mad [expr {median(abs($x - median($x)))}]
This typically is needed when post-processing some measurement data series.
AMB - 2025-06-05 03:45:59
Yeah, I guess I was just getting fed up with it. I'm finding that it would break far more than I originally thought it might. Also, I found this page of the wiki: expr shorthand for Tcl9. I am late to this party, ignore this page and refer to the other page.
AMB - 2025-06-05 04:09:14
Your example about median absolute deviation of a dataset, however, is addressed in a pure-Tcl package that I developed called ndlist.
Here is what you would do:
package require ndlist namespace import ndlist::* set x {4.2 2.4 3.1 2.8 9.3} set mad [median [nexpr {abs(@x - [median $x])}]]; # although I would calculate [median $x] first for performance puts $mad; # 0.7000000000000002
nexpr uses @name to specify a looping variable. It auto-detects the rank of the input tensors and will loop over n-dimensional lists.
KSA Interesting, I will have a look at the ndlist package!
I did some experiments on my own replacing the math functions within ::tcl::mathfunc namespace so that they can handle lists/vectors. The approach works quite well and breaks no code. The only drawback is I was unable to replace operators (+,-,*,...) in the same way. It seems non-trivial to do so because they are related to Tcl's optimizer. So I simply added new functions like add(), sub(), mul() which can handle lists/vectors - this works, but is not elegant.
aplsimple - 2025-06-05 10:35:08
I once suggested on Stackoverflow using single quotes parallel with braces, with the same sense (i.e. no substitutions), and Donal explained me in simple terms all the dangers of this way, mostly on breaking code. Say, set mylinuxcommand 'dir' would be broken. But, if the massive use of expr is supposed, why not use the code snippet feature of your editor, if it provides it? Then you just press a hot key (e.g. Alt+E or Alt+X) and get under the cursor [expr { | }] where | denotes the new cursor position. After that you type an expression.
AMB - 2025-06-05 13:35:05
You could use code snippets to automate writing [expr {…}], but the issue is that for such a common thing it clutters code and makes it difficult to read.
I’m leaning towards proposing the syntax [{math}] instead, where the command parser would be modified to interpret a command whose first word is in curly braces to be math (and throw an error if it has more args after). I don’t know of any current use case where a command name is wrapped in curly braces, so it might be able to be implemented without breaking anything.
AMB - 2025-06-05 16:03:35
I posted a proof-of-concept Tcl script that spoofs the modified parser for [{math}]. Check it out on the page expr shorthand for Tcl9.
FM What about it when we want to eval a command with space ?
set x [{command with space}]
I would prefer a math prefix, as this syntax raise an error
set x {=}$y+1
aplsimple - 2025-06-06 01:51:45
This example shows a need of expanding the set command, just to have spaces in math expressions, for the same expressiveness wanted here. If so, why not have the following syntax of set:
set x = 1.23 * $x + $y/12.3
... or introduce let command instead?
Then, as NR proposed, get rid of dollars as they clutter the code too. Then replace sqrt with its math character as it looks non-mathematically. And so on and on...
Dreams, dreams... The real answer to the problem of massive math calculations (if they are present in a Tcl project) is moving them to a C module, with two nice results - performance and expressiveness. What are Tcl-C interfaces (e.g. CFFI Package) designed for if not for these cases?
FM answer to aplsimple : I'd like a more generic syntax principle. IMHO, the one with the prefix is more flexible.
set x {num}sqrt($x**2,$y**2) ; # compute numbers with math language set s {string}$word1+" "*2+$word2; # concat $word1 with 2 spaces then with $word2 set add {c_code}{ int add (int a, int b) {return a+b} } ; # this could be compile as c function. apply $add 1 2
.c add text {num}$x+30 {num}$y+100 -text {string}Welcome+" "+$userName
interp prefix create vec3 {x y z} { return [uplevel {list [expr {$x}] [expr {$y}] [expr {$z}]}] } set V {vec3}[list $x+30 $y+10 $z+50]
To summarize, I imagine a new syntax rule, with a new concept, let's say « annotation prefix », whose goal would be to give the ability to modulate the interpretation of an annotated word by the parser.
AMB - 2025-06-06 04:23:19
RE: FM The proposed [{math}] syntax would admittedly break any code where you had a command name with spaces in it that was surrounded with braces. I scanned all the Tcl library files in an ActiveState Tcl installation, which included Tcllib and dozens of other standard libraries, and this syntax never came up. In the rare case that you did have a command with spaces in it, this change would require that you surround it in quotes or put it in a variable or as the result of a command. I don’t mind there being a restriction that command names (the first word in a Tcl expression) cannot be braced, but yes it would add another rule to Tcl.
RE : AMB But I think it's possible to have a more generic syntax rule (see « annotation prefix » proposal above), more powerfull, giving more capabilities to the language, not constraints to mathematics only, and, morover, without breaking any older code. Ok, maybe I'm dreaming...
AMB - 2025-06-06 13:35:53
The {=} prefix is mentioned in the page expr shorthand for Tcl9, and I am not opposed to it, it is similar to the {*} syntax for expanding arguments. I think it would have to be like {=}{math} to avoid any double-substitution.
Comparison:
set x [expr {1+2}] set x {=}{1+2} set x [{1+2}]
I guess the {=} prefix is only one more character, maybe you are right, it might be the way forward. It would remove four characters per math expression, my proposed implementation only goes one character further.
FM answer : if the prefixes are recognized by the parser, the prefixed words will be parse till their end, before being eval recursively. So i think it's possible to avoid double substitution this way. We even don't need to enclose it with braces, as far as there is no space in it.
set x {=}1+2 # or set x {num}1+2
aplsimple - 2025-06-06 13:46:01
FM : You mean that the following code would be possible:
set z {=}{1.23 * $x + $y/12.3} set z {=}"1.23 * $x + $y/12.3" set z {num}{1.23 * $x + $y/12.3} set z {num}"1.23 * $x + $y/12.3" set s1 abcdef set s2 cde set s3 def puts {str}$s1+$s2 ;# => abcdefcde == $s1$s2 puts {str}$s1-$s2 ;# => abf puts {str}$s3+($s1-$s3) ;# => defabc
... and so on and on...
( if num instead of number, why not str instead of string? )
That would be a cool new feature of Tcl! Nicely expanded at that. Is there a TIP for it?
FM answer : Yes, this is exactly what i was meaning. No, there is no TIP as I don't have competence to do it.
AMB - 2025-06-06 14:19:05
Thinking about it more, you are right, the prefix is the most sensible approach as it is already implemented with the {*} prefix. A friend mentioned to me that python has something similar with “f strings”, so it would be consistent with other popular languages as well.
The ability to add a new prefix to the interpreter would allow people to create their own expr-like language, perhaps one that does not require a $ to reference variables. Like, you could have the prefix {m} for a more natural math syntax or something. I especially like your idea of being able to alias a prefix to a command.
AMB - 2025-06-06 14:21:17
Re: aplsimple I don’t think there is a TIP for it, but there should be.
AMB - 2025-06-06 14:51:51
Looking through the TIPs, there are some similar proposals out there, but nothing yet for a math prefix.
FM : very happy to see you both like the proposal. But i don't know if it's feasible... I'd like to have the opinion of a core développer.
AMB - 2025-06-06 18:22:32
RE: FM I was thinking about it more, and I came up with a slightly different format: {$}{math}, where you don't have to use $ sign substitution in the math expression. There would be limits to the variable names for this sort of math language, but it would look a bit like this:
With {$}{math} syntax:
set x 5.0 set y {$}{x * 2} set z {$}{x + y} puts [list {$}{x + 2.0*(y*max(x,z) - x*y)} {$}{x*y*z**2}]
With regular expr command:
set x 5.0 set y [expr {$x * 2}] set z [expr {$x + $y}] puts [list [expr {$x + 2.0*($y*max($x,$z) - $x*$y)}] [expr {$x*$y*$z**2}]]; # saved 17 characters!!
I think that there should also be a "math" function or something similar that the {$} syntax is short for. You could also add "info ismathvar" or something to validate the math variable name.
The benefit to this approach is that it would not touch expr at all, but rather add a new math parser command that has an alias {$}, signaling that you don't have to use $ for substitution within the expression. I tried to see how it felt to type out {=}{...} a bunch of times and it was clunky. {$}{...} is much easier, because you can hold down the shift key while doing it. It honestly looks and feels right.
This would admittedly be a big undertaking (more than I can tackle this weekend lol), but I think that it could open up a lot for the Tcl language.
FM answer to AMB : Well, to get rid of the dollars sign is a matter of taste : as I'm used to (I practiced korn shell), I'm not bother with it. But, if there were a command
interp prefix {} wordPrefix command
people could try this kind of experiment...
On another page, see Proposal of syntax, expressiveness and semantic improvements with annotations, I explored futher this concept of annotation, and generalized it to many situations (ex: specifying argument of proc). One idea was to generalize the parenthesis construct to acces part of complex variable, for instance when writing :
set {list}L(0) 1 set {dict}D($key) $value set {matrix[3,3]}M(0,0) $val
it would result in
lset L 0 1 dict set D $key $value lset M 0 0 $val
Another desirable feature is multiline expression and variable affectation in it. Some TIP exist on those subjects.
Taking all this together, instead of writing
proc matmul {matrix vector} { set n1 11 set n2 12 set n3 13 foreach row $matrix { foreach [list m$n1 m$n2 m$n3] $row { break } incr n1 10 incr n2 10 incr n3 10 } set r [list] foreach v $vector { foreach {x y z} $v { break } lappend r [list [expr {$m11*$x+$m12*$y+$m13*$z}] \ [expr {$m21*$x+$m22*$y+$m23*$z}] \ [expr {$m31*$x+$m32*$y+$m33*$z}] ] } return $r }
which needs 437 chars to be written and is difficult to read, we could write, with multiline expression and looping constructs include into it,
we could write something like this :
proc matmul { {matrix[3,3]}Mi {matrix[3,3]}Mj }{ return {=}{ R = {matrix[3,3]}[lrepeat 3 [lrepeat 3 0.0]]; for(i=0, \$i < 3, i++, {=}{ for(j=0, \$j < 3, j++, {=}{ R($i,$j) = $Mi($i,0)*$Mj(0,$j) + $Mi($i,1)*$Mj(1,$j) + $Mi($i,2)*$Mj(2,$j) }) }) } }
wich needs only 280 chars and that I find more explicit. If possible, the annotation {Matrix[3,3]} would result in a custom object, with efficient Matrix representation.
AMB - 2025-06-07 16:13:03
I agree that the ability to define custom prefixes would be ideal for testing out this feature. We already have {*} for argument expansion, and {#} has been proposed for comments within long command calls. Creating a “prefix” option for the interpreter would allow the Tcl community to experiment with what syntax is preferred, and then the consensus could be implemented in the core. (FM : you are right, this interp prefix should be where to begin. A too complex proposal can't reach consensus yet.)