I've implemented a working prototype of TIP 672 - the $(expression) syntax for Tcl.
Instead of:
set result [expr {$a + $b * $c}]
puts "Total: [expr {$sum + $tax}]"
You can now write:
set result $($a + $b * $c)
puts "Total: $($sum + $tax)"
Thoughts? Does anyone see issues I haven't considered?
et99 <et99@rocketship1.me> wrote:
I've implemented a working prototype of TIP 672 - the $(expression) syntax for Tcl....
Instead of:
set result [expr {$a + $b * $c}]
puts "Total: [expr {$sum + $tax}]"
You can now write:
set result $($a + $b * $c)
puts "Total: $($sum + $tax)"
Thoughts? Does anyone see issues I haven't considered?
It conflicts with "empty string array names":
$ rlwrap tclsh
% set tcl_patchLevel
8.6.12
% array set "" [list a 1 b 2 c 4]
% array get ""
a 1 b 2 c 4
% puts $(c)
4
% puts $(a)
1
%
Now, naming an array "" is not commonly done, but I've used it (empty string) sometimes for the destination array for ::cmdline::getopt and friends for storing command line argument options.
Rich <rich@example.invalid> wrote:
et99 <et99@rocketship1.me> wrote:
I've implemented a working prototype of TIP 672 - the $(expression) syntax for Tcl....
Instead of:
set result [expr {$a + $b * $c}]
puts "Total: [expr {$sum + $tax}]"
You can now write:
set result $($a + $b * $c)
puts "Total: $($sum + $tax)"
Thoughts? Does anyone see issues I haven't considered?
It conflicts with "empty string array names":
$ rlwrap tclsh
% set tcl_patchLevel
8.6.12
% array set "" [list a 1 b 2 c 4]
% array get ""
a 1 b 2 c 4
% puts $(c)
4
% puts $(a)
1
%
Now, naming an array "" is not commonly done, but I've used it (empty
string) sometimes for the destination array for ::cmdline::getopt and
friends for storing command line argument options.
Just noticed that the "Tcl" manpage explicitly defines empty string as
a valid array name (emphasis added below):
Rule #8:
$name(index) Name gives the name of an array variable and index
gives the name of an element within that array. Name
must contain only letters, digits, underscores, and
namespace separators, and **may be an empty string**.
On 10/17/2025 7:51 PM, Rich wrote:[snip]
Rich <rich@example.invalid> wrote:
et99 <et99@rocketship1.me> wrote:
I've implemented a working prototype of TIP 672 - the $(expression) syntax for Tcl....
Instead of:
set result [expr {$a + $b * $c}]
puts "Total: [expr {$sum + $tax}]"
You can now write:
set result $($a + $b * $c)
puts "Total: $($sum + $tax)"
Thoughts? Does anyone see issues I haven't considered?
This TIP was written to solve two issues with [expr]. if you look at the second reason mentioned in the TIP: that it improves security, I think you might find it a useful change for the 9.x system, given that only a minor change to coding would be required if one really still wants to use the array with no name.
Also, this TIP has no sponsor and has not been voted on. I am simply telling the tcl world that they can experiment (find bugs, express opinions on its implementation etc., tell me it's an awful idea) and otherwise play around with the change. Until now, one had to use JimTcl to test out this feature. Now it works in the very latest 9.1 Tcl.
-et99
On Fri, 17 Oct 2025 23:04:51 -0700, et99 wrote:[snip]
On 10/17/2025 7:51 PM, Rich wrote:
Rich <rich@example.invalid> wrote:
et99 <et99@rocketship1.me> wrote:
I've implemented a working prototype of TIP 672 - the $(expression) syntax for Tcl....
Instead of:
set result [expr {$a + $b * $c}]
puts "Total: [expr {$sum + $tax}]"
You can now write:
set result $($a + $b * $c)
puts "Total: $($sum + $tax)"
As an ordinary user I find this new syntax very appealing
and I hope it is adopted.
(Bikeshedding: regarding the parentheses, given that they
conflict with array syntax (in one rare case?) would an
alternative pair of delimiters work? For example:
set result $<$a + $b * $c>
puts "Total: $<$sum + $tax>"
Although presumably this would conflict with variable `$<`
which I suppose a Tcl refugee from Perl might use.)
On 10/18/2025 12:18 AM, Mark Summerfield wrote:
On Fri, 17 Oct 2025 23:04:51 -0700, et99 wrote:[snip]
On 10/17/2025 7:51 PM, Rich wrote:
Rich <rich@example.invalid> wrote:
et99 <et99@rocketship1.me> wrote:
I've implemented a working prototype of TIP 672 - the $(expression) syntax for Tcl....
Instead of:
set result [expr {$a + $b * $c}]
puts "Total: [expr {$sum + $tax}]"
You can now write:
set result $($a + $b * $c)
puts "Total: $($sum + $tax)"
As an ordinary user I find this new syntax very appealing
and I hope it is adopted.
(Bikeshedding: regarding the parentheses, given that they
conflict with array syntax (in one rare case?) would an
alternative pair of delimiters work? For example:
set result $<$a + $b * $c>
puts "Total: $<$sum + $tax>"
Although presumably this would conflict with variable `$<`
which I suppose a Tcl refugee from Perl might use.)
Thanks for the positive feedback!
Regarding alternative delimiters - parentheses were chosen for several reasons:
1. Jim Tcl precedent - They've used $(...) successfully for years, proving it works in practice
2. Limited options - Tcl already uses [] for command substitution and {} for grouping/quoting. That leaves only <> and () as symmetrical ascii paired delimiters (using `' would seem odd).
3. Avoids escaping problems - Using <> would require escaping comparison operators:
$<$a \<= $b> # Need to escape <=, >=, <, >
$($a <= $b) # No escaping needed
4. Natural pairing - Parentheses nest and balance automatically, which is crucial for complex expressions
5. Common in expressions - Every language uses () for grouping: $(($a + $b) * $c) reads naturally
The empty array name conflict is real but extremely rare, and easily worked around with ${(index)} or [set (index)] when needed.
It's also worth noting that Tcl already has special-case code to handle empty array names - they're not a natural part of the array syntax. This suggests they were always an edge case rather than a core feature. Moving forward with $(...) in Tcl 9.x could actually simplify the parser by removing one special case while adding a more useful feature.
--et99
I've implemented a working prototype of TIP 672 - the $(expression)
syntax for Tcl.
I do like the idea of having {*}{expression} as one instance of a
generalised expansion system as proposed in https://wiki.tcl-lang.org/page/Expanding+the+Expansion+Prefix
but perhaps that's too radical.
et99 <et99@rocketship1.me> posted:
I've implemented a working prototype of TIP 672 - the $(expression)
syntax for Tcl.
Implementing this would make my TIP 676 redundant, but I wouldn't shed
any tears for that: https://core.tcl-lang.org/tips/doc/trunk/tip/676.md
This notation is more compact and has a simpler implementation than mine.
I do like the idea of having {*}{expression} as one instance of a
generalised expansion system as proposed in https://wiki.tcl-lang.org/page/Expanding+the+Expansion+Prefix
but perhaps that's too radical.
I certainly agree that a streamlined expression syntax would eliminate
one of the biggest warts that tends to put people off Tcl.
I've implemented a working prototype of TIP 672 - the $(expression)
syntax for Tcl.
Instead of:
set result [expr {$a + $b * $c}]
puts "Total: [expr {$sum + $tax}]"
You can now write:
set result $($a + $b * $c)
puts "Total: $($sum + $tax)"
It compiles to identical bytecode as [expr {...}], so there's no
performance penalty. Works great in strings, procs, and interactive mode.
Repository with code and examples in the readme (with details about the
new code):
https://github.com/rocketship88/tcl-tip-672-prototype
The code is based on Tcl 9.1 source from last week, so the modified
files should drop into current builds without conflicts to easily test
this prototype.
The implementation is surprisingly simple - about 100 lines across two
files in tclParse.c and tclNamesp.c. It creates a synthetic [expr {...}] string that the existing compiler optimizes normally.
One limitation: the synthetic strings leak memory (need core team input
on the cleanup mechanism). Otherwise it's been working well in testing.
Thoughts? Does anyone see issues I haven't considered?
-et99
On 18/10/25 09:23, et99 wrote:
I've implemented a working prototype of TIP 672 - the $(expression) syntax for Tcl.Oh yes, I love that. I've been sticking to 8.6 on our work servers, because if it ain't broke ... but I'd definitely upgrade to 9 for that alone.
Instead of:
set result [expr {$a + $b * $c}]
puts "Total: [expr {$sum + $tax}]"
You can now write:
set result $($a + $b * $c)
puts "Total: $($sum + $tax)"
It compiles to identical bytecode as [expr {...}], so there's no performance penalty. Works great in strings, procs, and interactive mode.
Repository with code and examples in the readme (with details about the new code):
https://github.com/rocketship88/tcl-tip-672-prototype
The code is based on Tcl 9.1 source from last week, so the modified files should drop into current builds without conflicts to easily test this prototype.
The implementation is surprisingly simple - about 100 lines across two files in tclParse.c and tclNamesp.c. It creates a synthetic [expr {...}] string that the existing compiler optimizes normally.
One limitation: the synthetic strings leak memory (need core team input on the cleanup mechanism). Otherwise it's been working well in testing.
Thoughts? Does anyone see issues I haven't considered?
-et99
Do general users get a chance to vote, if this is at a voteable stage?
Jonathan.
Thoughts? Does anyone see issues I haven't considered?
It conflicts with "empty string array names":
Now, naming an array "" is not commonly done, but I've used it (empty
string) sometimes for the destination array for ::cmdline::getopt and
friends for storing command line argument options.
On 10/17/2025 10:48 PM, Rich wrote:
...
Thoughts? Does anyone see issues I haven't considered?
It conflicts with "empty string array names":
Now, naming an array "" is not commonly done, but I've used it (empty
string) sometimes for the destination array for ::cmdline::getopt and
friends for storing command line argument options.
That is one of the two things that came to my mind.
Personally, I am kind of surprised that "expr {}" seems to be disliked.
I also don't see how "$()" improves things but that's just me.
Personally, I am kind of surprised that "expr {}" seems to be disliked.
I also don't see how "$()" improves things but that's just me.
It is identical to Bash's process substitution operator [1], beyond that,
it is less characters than [expr {}].
But I very much suspect that it will do little to quiet the complaints
from "other language users" who complain about [expr]. It will change
their complaints, but it won't quiet them. Because what they are
really complaining about is they want to see something like this:
some-func $a+$c ($ab+$cd/($ef-$gh))
Or more likely, what they 'really' are complaining about is that Tcl
does not look like this to them:
some-func a+c (ab+cd/(ef-gh))
On 10/17/2025 10:48 PM, Rich wrote:
...
Thoughts? Does anyone see issues I haven't considered?
It conflicts with "empty string array names":
Now, naming an array "" is not commonly done, but I've used it (empty
string) sometimes for the destination array for ::cmdline::getopt and
friends for storing command line argument options.
That is one of the two things that came to my mind.
The other one is the evaluation order of individual words that make up a command. Currently, everything between curly braces "{}" are delayed for variable substitutions, command evaluations, etc.
However, it looks like stuff between "$(" and the matching ")" are treated same as "{}", which would alter the basic rules of the language.
Perhaps adopting a new syntax like "{**}{...}" or even "{=}{...}" like someone else suggested, might be easier to pull into the current rules.
Personally, I am kind of surprised that "expr {}" seems to be disliked. I also don't see how "$()" improves things but that's just me.
Interesting project.
On 10/19/2025 4:11 PM, Rich wrote:
But I very much suspect that it will do little to quiet the complaints
from "other language users" who complain about [expr]. It will change
their complaints, but it won't quiet them. Because what they are
really complaining about is they want to see something like this:
some-func $a+$c ($ab+$cd/($ef-$gh))
Or more likely, what they 'really' are complaining about is that Tcl
does not look like this to them:
some-func a+c (ab+cd/(ef-gh))
It makes sense now and I agree. I see it as, everything comes with their own quirks, like roses and their thorns, so perhaps this is something about Tcl that we just need to accept with no apologies.
However, it just occurred to me that perhaps there is a better defense, and I am not certain there needs to be one:
The desired syntax (from your examples above) is limited in functionality: it performs the calculations once, right there. To have it repeated on events, triggers, etc., one will need to write a function around these expressions.
However, Tcl offers more flexibility: you can have your expressions inlined as above, or you can have them execute later, without any extra set up or wrapper functions.
Just my 2 cents I guess.
Regarding saito's point on immediate vs. delayed values: $(...) works exactly the same as $var in this regard - nothing new to learn.
On 10/19/2025 11:46 PM, et99 wrote:
Thank you. I got that impression from your post from the start. What I was hinting at was that, the 12 rules of the language would have to be modified because of the word/argument expansion semantics which is suppressed only for curly braces. Unless I am mistaken, the "$(...)" would need to be added as an exception or a new rule or something like that.
Regarding saito's point on immediate vs. delayed values: $(...) works exactly the same as $var in this regard - nothing new to learn.
On 10/20/2025 11:45 AM, saito wrote:
Thank you. I got that impression from your post from the start. What I was hinting at was that, the 12 rules of the language would have to be modified because of the word/argument expansion semantics which is suppressed only for curly braces. Unless I am mistaken, the "$(...)" would need to be added as an exception or a new rule or something like that.
On 10/18/2025 4:30 AM, Colin Macleod wrote:
I certainly agree that a streamlined expression syntax would eliminate
one of the biggest warts that tends to put people off Tcl.
Thank you for the support and for your willingness to consolidate efforts! It's encouraging to see convergence around addressing this long-standing issue.
et99 <et99@rocketship1.me> posted:
On 10/18/2025 4:30 AM, Colin Macleod wrote:
I certainly agree that a streamlined expression syntax would eliminate
one of the biggest warts that tends to put people off Tcl.
Thank you for the support and for your willingness to consolidate efforts! >> It's encouraging to see convergence around addressing this long-standing issue.
After seeing lots of quibbling about compatibility on the tcl-core list
I'm thinking maybe it's not yet time to write off my own suggestion.
So I sent the following to tcl-core:
========================================================================
Hi All, perhaps it's time to boost my own expr proposal again.
I like the [= <expr>] idea, but simply aliasing "=" to expr doesn't help
much because you still need to brace the expression to avoid double- substitution problems. Unbraced works ok for the simple examples Florent gives, but in general is problematic, e.g.
set x {[exec cat /secret/file >/dev/tty]} ;# x might be set from user input
...
string range "abcdef" 1 end-[= $x-2] ;# user sees secret file :-(
My own TIP 676 is a proposal to make [= <expression>] usable and safe.
It has the advantage of not requiring any change to the dodekalogue and
is fully compatible with existing code. It also can be used anywhere
that [] gets expanded including within quoted strings, which is not the
case for the {=}{expr} proposal.
There are some downsides:
- Operators and operands need to be separated with spaces, i.e. [= $x - 2]
not [= $x-2]
- Only numerical and boolean values can be supported, not string values
- Lazy evaluation of && || ?: is not supported
- The implementation is a little more complicated since it can't use the
existing [expr] parser. I supplied a Tcl prototype, linked from the TIP,
actual implementation would require translating this into C.
I worked on this in 2023 but put it aside because everyone was focussed
on getting 9.0 released, then I moved on to a different project. I think it's worth considering now that [expr] simplification is back in the spotlight.
Colin. ========================================================================
My TIP is at https://core.tcl-lang.org/tips/doc/trunk/tip/676.md .
I do think any of the proposals on the table would be better than
doing nothing though.
I've modified my code to have a #define mode option which can
implement either of the original syntax $(...) or Don's idea of
$=(...) where the = could be any of the non-substitution characters,
like @ or ^ which I believe eliminates the conflict with the null
string array variable name. Just 1 extra character.
I was encouraged to find that several core team members were quite supportive, but I needed to finalize my prototype and let them make
the next move.
Equals seems fine as a character, and at least suggests "math" as well
as making a math equation somewhat read like a written one:
set a $=($y*4+$z**2) ;# set a "equals" to 4*$y plus $z squared
It also, it seems, does not conflict with any existing code usage of $
as $= does not expand:
$ rlwrap tclsh
% array set = [list a 1 b 2 c 3]
% puts $=(b)
$=(b)
% puts $=(b)
$=(b)
% set =(b)
2
% puts ${=(b)}
2
So while one can have an array named =, one could not use plain $=() to access it, so using $= for your new math operator won't conflict with
any existing code (which would have already had to use 'set' or ${} to
access an "array named equals").
I suggest falling behind the $=() syntax, as it looks to remove *any* complaints of breaking legacy code.
Sysop: | DaiTengu |
---|---|
Location: | Appleton, WI |
Users: | 1,073 |
Nodes: | 10 (0 / 10) |
Uptime: | 222:42:56 |
Calls: | 13,783 |
Calls today: | 1 |
Files: | 186,987 |
D/L today: |
705 files (243M bytes) |
Messages: | 2,434,876 |