TIP 759

Difference between version 15 and 26 - Previous - Next
[FM] https://core.tcl-lang.org/tips/doc/trunk/tip/759.md%|%TIP 759%|% is a proposition whose goal is to facilitate arithmetic calculations with Tcl. The prototype can be found at its dedicated https://core.tcl-lang.org/tcl/timeline?r=tip-759_tcl90%|%branch%|%

The features offered fall into three categories:

  
   * Extensions to the expr language :   
   ** An ability to assign values ​​to variables ('''TIP 282 Assignment operator''')
   ** An ability to chain calculations ('''TIP 282 Separating operator''')
   ** Simplifying the definition of lists of numbers ('''Parentheses-comma list operator''')
   **  Recognizing arithmetic substitution ('''Arithmetic TOKEN''')
   * More direct access from the command line ('''Arithmetic substitution''')
   * An ability to define arithmetic scripts : ('''Arithmetic compilation''')

You can refer to the text of the TIP to see more details.

It came out during a very long discussion whith [AMB] in the page [https://wiki.tcl-lang.org/page/A+Better+way+to+do+calculations]. I have to thank Eric Taylor also ([ET]), who gave me great insights on the Tcl core code style.
'''<News>''' (2026/09/25) : After the discussion with [NR] (see below), I added the possibility to call some commands from expr. The implementation can be found in the https://core.tcl-lang.org/tcl/timeline?r=tip-759b_tcl90%|%tip-759b_tcl90 branch%|%. A command is called using command syntax., Bits arguments iare space separated. mu. 

'''<News>''' (2026/10/05) : the bend of the clommand is set to bye athe next expr (ascii) opemrator, i-ncoluding close paren.thesis, like *,+/?!=^|~%):;-

   * Extensions to the expr language :   ** Allow the call of a restricted set of commands (`dict for*`, `dicstring map*`, `for`, `foreach`, `if`, `lmap`, `return`, `switch`, `while`, `concat`, `lindex`, `lappend`, `lassign`, `llength`, `incr`) : those commands names are hard-coded and recognized by ParseLexeme producing a new Token type : TCL_TOKEN_CMD_IN_EXPR. The boudaries of this new Token is defined to be from the begining of the command name to the char just before next ascii operator `;,):!?<>/*+-&|~=`, or to the end of the parsed string. This last operator, if any, is taken by expr as an operator. That allows to avoid the use of brackets in simple cases. Notice also that TCL_TOKEN_CMD_IN_EXPR is not representative of one command only. Many commands separated by newlines can be chained.
Example of usage : 
   **E A matrix product : (The first `foreach` command is called from ''arithmetic syntax'', and has a body in ''command syntax''. The second `foreach` is called from ''command syntax'' but has a body in ''arithmetic syntax''. NB : This proc is allmost twice faster than the code in [Matrix Multiplication]) :
======
proc matrixProduct {A B} {(
    foreach Arow $A Brow $B \
      aMap {{a00 a01 a02} {a10 a11 a12} {a20 a21 a22}}\
      bMap {{b00 b01 b02} {b10 b11 b12} {b20 b21 b22}} {
        foreach valA $Arow valB $Brow varA $aMap varB $bMap {( $varA = $valA;  $varB = $valB )}
    }; 
    # Return the product of matrixes, using formula.
    # First row :
    (($a00*$b00 + $a01*$b10 + $a02*$b20),
     ($a00*$b01 + $a01*$b11 + $a02*$b21),
     ($a00*$b02 + $a01*$b12 + $a02*$b22)),
    # Second row :
    (($a10*$b00 + $a11*$b10 + $a12*$b20),
     ($a10*$b01 + $a11*$b11 + $a12*$b21),
     ($a10*$b02 + $a11*$b12 + $a12*$b22)),
    # Third row :
    (($a20*$b00 + $a21*$b10 + $a22*$b20),
     ($a20*$b01 + $a21*$b11 + $a22*$b21),
     ($a20*$b02 + $a21*$b12 + $a22*$b22))
)}
======
   * Many commands can be chained if they are separated by newlines :
======
proc test {} {(
 s=0;
 foreach i {1 2 3} {(s=$s+$i)}
 foreach j {4 5 6} {(s=$s+$j)} 
 ;
 return $s;
)}
if 0 {
% test
 21
}
======
`if`, `while`, `for` are impacted, since internally, they are using expr parser/compiler : Eg :
======
set L {1 2 3}
if {llength $L == 3} {(
    s = 0;
    for (i=0) {$i < llength $L} {incr i} {(
       s = $s + lindex $L $i
    )}
)}
======
Notice that `llength` and `lindex` don't need brackets anymore. But you may still use brackets if you like.
**Examples in the wiki**

   * [Quaternion made simple]
   * [3D polyhedra with simple tk canvas] (adapted from)
----
'''[NR] - 2026-09-18 17:55:12'''

Hello Florent, I think the idea is interesting, especially for numerical and mathematical code. My main concern is more about readability.

Looking at the complete [3D polyhedra with simple tk canvas] example, I find that there is quite a lot of Tcl and mathematical syntax mixed together. With (...), \[(...)], \[foreach {()}], substitutions and regular Tcl scripts appearing within the same procedures, it can sometimes be difficult to tell at a glance where Tcl ends and the mathematical syntax begins.

I actually have a math package myself, so I know the problem you are trying to address. There are places in my own code where expressing mathematical operations in Tcl becomes quite cumbersome. For example, I have this line in one of my quaternion tests:

======
set q29 [[[[[[[[$q2 * $q2] * $q2] * $q2] * $q2] * $q2] * $q2] * $q2] * $q2]
======


This is quite extreme just to express repeated multiplication, and it is a good example of why I understand the motivation behind TIP 759.

Interestingly, I already have a ^ operator in my Quaternion package, so this particular example could simply be written as:

======
set q29 [$q2 ^ 9]
======


At the same time, I don’t really have a better solution myself, and I certainly wouldn’t have been able to come up with something like your approach.

I wonder if the concept might also work well as a separate package, perhaps with something like a ‘math::proc’ construct. This could provide a clearer boundary between regular Tcl code and the mathematical part, while still offering the benefits of the new syntax.

For example:


======
math::proc CrossProduct {x1 y1 z1 x2 y2 z2} {(
    $y1*$z2 - $y2*$z1,
    $z1*$x2 - $z2*$x1,
    $x1*$y2 - $x2*$y1
)}
======

In a function like this, I actually wouldn’t want to have other Tcl commands mixed into the mathematical expression. I would prefer the whole body to clearly be “the mathematical part”, with the boundary to regular Tcl being explicit.

Of course, my opinion is just one perspective here. I can clearly see how enthusiastic you are about the idea, especially from the amount of existing Tcl code you have already transformed using the concept. That’s actually what made me look more closely at the result and think about how it feels in a larger, real-world example.

For me, the interesting question is perhaps less about whether the mathematical syntax is useful, and more about how clearly we can separate the two worlds. In the current examples, I feel there is quite a lot of mixing between Tcl and math.

And of course, I may simply have misunderstood the intent of the TIP. If so, I apologize in advance!
----
Hi [NR]. You understood pretty well the intent of the TIP. What you are explaining is true. We can mix command syntax in arithmetic syntax, and arithmetic syntax in command syntax. So we may shift from one syntax to another frequently. It can be disturbing. But '''Subscripts must be recognized''' in arithmetic syntax. If they were not, something as simple as retrieving an element of a list would become impossible. 
======
# Arithmetic Syntax :
...
v = [lindex $L 0];
...
======
We have not choice : we must allow to cross the bounderies... So, if the TIP is accepted, there should be a "good practice" guideline. The number of nested levels should be minimized. 

Something I found displeasant is when I have to use the arithmetic substitution again in a nested command script
======
# Arithmetic Syntax :
...
v = [lindex $L [($i*2)] ];
...
======
Maybe a solution would be to have a special mode of command parsing, when this command is parsed from a arithmetic script. Let's say, in this situation, `)` will be taken as a word terminator, and then a word like `(...)` would be parsed as an expression :  
======
# Arithmetic Syntax :
...
v = [lindex $L ($i*2)];
...
======AFor vthis solution, I should be able to triansmit the fact that we are coumpiling a command form expr arithmetic syntax. The path for this compilation is : <<br>>
`Tcl_CompileExprTree` -> `Tcl_CompileToken` -> `Tcl_CompileScript` -> `Tcl_ParseCommand`<<br>>
But ''no paramevter exists in the prototypes of those functions to transmit this kind of information. The only possibility would be to add a field in the compile Env structure.

So I choose to introduce `Raw command` in expr. The boundaries of this new command Token is'' defined (in short) from the begining of a command name (detected in `ParseLexem`) to the char just before the nexet ascii operator. This permits to avoid the use of the first level of brackets
======
# Arithmetic Syntax :
...v = [lindex $L )$i*2(];
r = [lrange ($L )$i*2()$j+3(];
...
======
ButA whgood practice is walsorking now, is to use '''variables''' to communicate between these two worlds. In practice, this var allocation as a cost in speed.
======
# Arithmetic Syntax :
...
j = $i*2;
v = [lindex $L $j];
...
======

About the abondance of symboles like in `\[foreach ... {()}];`
FMy first idea was to create a `Foreach` mathfunc, with a body in arithmetic syntax, we then would write : `Foreach("i",$L,{ ... });`
But this is slow (`uplevel`). We have to use comas, we to quote the arguments... It's not more clear. There is no gain, finally.
So Aa new idea came to me : it should be possible to define "COMMAND" leaf lexem type and make expr to call Tcl_ParseCommand (but not nested ..), which would then make a parse... in command syntax till the next newlascinei or spemi-cratolonr. Then we can write :
======
proc test {} {(
   A = (1,2,3);
   foreach i $A {( 
      ...
   )};
   B = (4,5,6);
   ...
)}
======It wouldis be a lot more clear !
Of course the set of commands to be recognized like this shomuldst be in a limited number, mainly restricted to commands that control the flow (for, while, switch, if, foreach, lmap)., commands that deals with data (dict, string, lindex, lappend, llength), commands that deals with variable (upvar, variable, global)
Would you prefer it like this ?
----
'''[NR] - 2026-09-19 08:12:20'''

Thanks, I think I understand the idea better now.

If I understand correctly, with your new approach the mathematical syntax remains the main context, and when the parser encounters one of the recognized Tcl commands, such as `foreach`, it switches temporarily to Tcl command syntax, then returns to the mathematical syntax afterwards.

So your example:

======
proc test {} {(
   A = (1,2,3);
   foreach i $A {(
      ...
   )};
)}
======

would roughly mean:

    * `{(` enters the mathematical syntax;

    * `A = (1,2,3);` is a mathematical statement;

    * `foreach i $A` is parsed as a Tcl command, and `{(` then switches back to mathematical syntax for its body;

    * `)}` returns from the mathematical syntax to Tcl;

    * `;` terminates the `foreach` command, and the parser then resumes the surrounding mathematical syntax;

    * `)}` finally leaves the outer mathematical syntax.

Is that the intended interpretation?

<[FM]> : '''yes Sir !''' </[FM]>

There is one thing about the `;` that I am still wondering about. In Tcl, `;` already has a very specific meaning: it terminates a Tcl command, for example:

======
set x 1; set y 2
======

So if `;` is also used as the marker telling the math parser to resume after a Tcl command, what happens with multiple Tcl commands on the same line?

For example, would something like this be possible?

======
foreach i $A {( ... )}; set x 10; set y 20
======
<[FM]> Tcl_parseCommand will return at the terminator, which is ''';'''. So expr will get a TCL_TOKEN_SCRIPT containing "`foreach i $A {( ... )};`". After the semi-colon, we are back to expr syntax, so there will be an error like "invalid barewords set" (if set is not recognized as a command in expr). You'll have to write :
======
foreach i $A {( ... )}; x=10; y=20
======
</[FM]>

And more generally, would a sequence of mathematical statements be allowed on the same line, or does the parser require a newline after each one?
<[FM]> TIP 759 introduce ";" as a separator. So you must separate instructions by ";". On thNe other end, newline has no meaning at all in expr.</[FM]>

I am also wondering about comments. Would normal Tcl comments still work in the Tcl parts, for example:

======
foreach i $A {(
    # some Tcl comment
    ...
)};
======

Or would comments need special handling once the parser is inside the mathematical syntax?

<[FM]> comments were already implemented in expr. All they need is to be followed by a newline. So you can add coments, as the examples are showing it.</[FM]>

I ask because one thing I really like about Tcl is that newlines and semicolons are generally interchangeable as command separators, and comments can appear naturally in the code. I am curious how those existing Tcl rules would interact with this parser-switching mechanism.

One other thing I was wondering about with your new `COMMAND` lexeme idea: once we are already inside the arithmetic syntax, could the body of a recognized Tcl command use just parentheses instead of `{(` and `)}`?

For example:

======
proc test {} {(
    A = (1,2,3);
    foreach i $A (
        ...
    );
)}
======

Would the parser be able to determine from the context that the `(` after `foreach i $A` starts the command body, while the parentheses in something like:

======
A = (1,2,3)
======

are part of the mathematical expression?

Or is there a parsing reason why the `{(` and `)}` would still be necessary?

<[FM]> the reason lay in the logic of the implementation. To compile it's body, the foreach command is calling the function Tcl_CompileScript. In this function, I made things so that if a script begins by ( and finish by ), then it will be compiled as an arithmetic expression. So we always have :
======
foreach i $L {
   # command syntax
}
foreach i $L {(
   # arithmetic syntax
)}
======To implement what you ask (use only parentheses to signal an arithmetic body) :
======
proc test {} {(
    A = (1,2,3);
    foreach i $A (
        ...
    );
)}
======I would have to signal to Tcl_ParseCommand that it is parsing a command from expr. That should be possible with the ''nested'' parameter of this procedure. Then Tcl_ParseCommand would have to treat parentheses as braces, asproducing a simple word. 

I'mn sthe expr configuration, the expr parser will detect ia SCRIPT TOKEN and store quit as a TCL_TOKEN_COMMAND (Here I had to create a new Token type TCL_TOKEN_CMD_IN_EXPR because the "inlined command" is not enclosed in blrackets). WhLater, the expr compiler d`Tcl_CompileExpr` will call `Tcl_CompileToken's` on that Tokenow. `Tcl_CompileTokens` howill then call `Tcl_CompisleScript`. `Tcl_CompileScript` will icall `Tcl_ParseCommand`. 

Sadly, `Tcl_CompileScript` only consider ac string, wthe one pointed by the Token. No extra-flag can be passed to it. Therefore, we hayve no simple way to signal to `Tcl_Pax,rseCommand` wthat it is called from expr. The only possibility to make this modulation would be to set par field in thes `CompileEnv` structure. That could be coherent, since this TIP introduce two contexts of compilation (command / arithmetics).
</[FM]>
----
'''[NR] - 2026-09-19 13:57:09'''

Thanks again for the detailed explanations. I understand the implementation much better now.

There is one more thing I would like to clarify. Outside of a proc body or another command body, would the following forms also work with the current implementation?

======
set value [(1 + 2)]
======
<[FM]> this works </[FM]>

With the opening parenthesis on the following line:

======
set value [(
    1 + 2
)]
======
<[FM]> this works. ParseExpr will parse till the closing paren., followed by the bracket. Newlines don't matter in expr </[FM]>

And, since `;` can be used to chain several arithmetic instructions, would this also work?

======
set value [(A = 1; B = 2; $A + $B)]
======
<[FM]> this works and returns `$A+$B`<<br>>
What you should know here : a trailling `;` will mute the expression. If you write :
======
set value [(A = 1; B = 2; $A + $B;)]
======
value is set to ""<<br>>
</[FM]>

And, in particular, would this multiline form work as well?

======
set value [
    (
        A = 1;
        B = 2;
        $A + $B
    )
]
======
<[FM]> this '''won't''' work. The opening parenthesis must immediately follow an open bracket, and the closing parenthesis must be immediately followed by a close bracket. 

You will get an error "unknown command '('"

</[FM]>

I am asking because I have seen similar expression-block constructs in other languages, where a parenthesized block can contain several statements and the value of the block is the value of its final expression.

I am mainly curious whether the last form is already possible with the current implementation, or whether the arithmetic parser requires the opening `(` to be immediately after the `[` in an arithmetic substitution.

<[FM]> Must be immediately after. The other way is doable, just have to add a loop on spaces to skip it. But i didn't want : If someone has a proc '(', he can shift it one space away from the bracket to use it</[FM]>

I also noticed that you use `{(...)}` for arithmetic bodies in cases such as `foreach` and `proc`, for example:

======
foreach i $A {(
    ...
)}
======

and:

======
proc test {} {(
    ...
)}
======

So I was wondering why the same idea is not used for a direct arithmetic block, for example:

======
set value {(
    A = 1;
    B = 2;
    $A + $B
)}
======

I assume this may be related to the fact that braces have an established meaning in Tcl, particularly with respect to substitutions. Is that the reason you use `\[(...)]` for arithmetic substitution instead?

<[FM]> i have to speak about the internals of Tcl to answer... There is the parser, and there is the compiler. 

The parser split a commands in words. Each word is the site of a set of substitutions (eventually empty) to produce one Tcl_Obj, collected in arrays which are then transmitted to commands. As the Tcl Parser takes words in braces like simple words, it doesn't make any substitution in it.

There is the compiler. It works only on already parsed strings. Some commands, like `foreach`, `proc`, `if`...etc are compiling some of there arguments (their body). I made in sure that, if this argument to be compiled is enclosed by parentheses, then it will be compiled as an expression, with arithmetic syntax (-> arithmetic compilation)

It turns out that the command `set` doesn't compile it's second argument. So the variable 'value' will get exactly the string that was written between the braces. To get this string substituted, you must use arithmetic substitution, aka : `\[(...)]`, so that the parser knows what it has to do.
</[FM]>
----
'''[NR] - 2026-09-19 15:58:27'''

Thanks for the clarifications. I understand the TIP much better now, as well as the way you rewrote the [3D polyhedra with simple tk canvas] example.