You can subscribe to this list here.
| 2000 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(19) |
Jul
(96) |
Aug
(144) |
Sep
(222) |
Oct
(496) |
Nov
(171) |
Dec
(6) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2001 |
Jan
(4) |
Feb
(4) |
Mar
(9) |
Apr
(4) |
May
(12) |
Jun
(6) |
Jul
|
Aug
|
Sep
(1) |
Oct
(2) |
Nov
|
Dec
|
| 2002 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(1) |
Jul
(52) |
Aug
(47) |
Sep
(47) |
Oct
(95) |
Nov
(56) |
Dec
(34) |
| 2003 |
Jan
(99) |
Feb
(116) |
Mar
(125) |
Apr
(99) |
May
(123) |
Jun
(69) |
Jul
(110) |
Aug
(130) |
Sep
(289) |
Oct
(211) |
Nov
(98) |
Dec
(140) |
| 2004 |
Jan
(85) |
Feb
(87) |
Mar
(342) |
Apr
(125) |
May
(101) |
Jun
(60) |
Jul
(151) |
Aug
(118) |
Sep
(162) |
Oct
(117) |
Nov
(125) |
Dec
(95) |
| 2005 |
Jan
(141) |
Feb
(54) |
Mar
(79) |
Apr
(83) |
May
(74) |
Jun
(125) |
Jul
(63) |
Aug
(89) |
Sep
(130) |
Oct
(89) |
Nov
(34) |
Dec
(39) |
| 2006 |
Jan
(98) |
Feb
(62) |
Mar
(56) |
Apr
(94) |
May
(169) |
Jun
(41) |
Jul
(34) |
Aug
(35) |
Sep
(132) |
Oct
(722) |
Nov
(381) |
Dec
(36) |
| 2007 |
Jan
(34) |
Feb
(174) |
Mar
(15) |
Apr
(35) |
May
(74) |
Jun
(15) |
Jul
(8) |
Aug
(18) |
Sep
(39) |
Oct
(125) |
Nov
(89) |
Dec
(129) |
| 2008 |
Jan
(176) |
Feb
(91) |
Mar
(69) |
Apr
(178) |
May
(310) |
Jun
(434) |
Jul
(171) |
Aug
(73) |
Sep
(187) |
Oct
(132) |
Nov
(259) |
Dec
(292) |
| 2009 |
Jan
(27) |
Feb
(54) |
Mar
(35) |
Apr
(54) |
May
(93) |
Jun
(10) |
Jul
(36) |
Aug
(36) |
Sep
(93) |
Oct
(52) |
Nov
(45) |
Dec
(74) |
| 2010 |
Jan
(20) |
Feb
(120) |
Mar
(165) |
Apr
(101) |
May
(56) |
Jun
(12) |
Jul
(73) |
Aug
(306) |
Sep
(154) |
Oct
(82) |
Nov
(63) |
Dec
(42) |
| 2011 |
Jan
(176) |
Feb
(86) |
Mar
(199) |
Apr
(86) |
May
(237) |
Jun
(50) |
Jul
(26) |
Aug
(56) |
Sep
(42) |
Oct
(62) |
Nov
(62) |
Dec
(52) |
| 2012 |
Jan
(35) |
Feb
(33) |
Mar
(128) |
Apr
(152) |
May
(133) |
Jun
(21) |
Jul
(74) |
Aug
(423) |
Sep
(165) |
Oct
(129) |
Nov
(387) |
Dec
(276) |
| 2013 |
Jan
(105) |
Feb
(30) |
Mar
(130) |
Apr
(42) |
May
(60) |
Jun
(79) |
Jul
(101) |
Aug
(46) |
Sep
(81) |
Oct
(14) |
Nov
(43) |
Dec
(4) |
| 2014 |
Jan
(25) |
Feb
(32) |
Mar
(30) |
Apr
(80) |
May
(42) |
Jun
(23) |
Jul
(68) |
Aug
(127) |
Sep
(112) |
Oct
(72) |
Nov
(29) |
Dec
(69) |
| 2015 |
Jan
(35) |
Feb
(49) |
Mar
(95) |
Apr
(10) |
May
(70) |
Jun
(64) |
Jul
(93) |
Aug
(85) |
Sep
(43) |
Oct
(38) |
Nov
(124) |
Dec
(29) |
| 2016 |
Jan
(253) |
Feb
(181) |
Mar
(132) |
Apr
(419) |
May
(68) |
Jun
(90) |
Jul
(52) |
Aug
(142) |
Sep
(131) |
Oct
(80) |
Nov
(84) |
Dec
(192) |
| 2017 |
Jan
(329) |
Feb
(842) |
Mar
(248) |
Apr
(85) |
May
(247) |
Jun
(186) |
Jul
(37) |
Aug
(73) |
Sep
(98) |
Oct
(108) |
Nov
(143) |
Dec
(143) |
| 2018 |
Jan
(155) |
Feb
(139) |
Mar
(72) |
Apr
(112) |
May
(82) |
Jun
(119) |
Jul
(24) |
Aug
(33) |
Sep
(179) |
Oct
(295) |
Nov
(111) |
Dec
(34) |
| 2019 |
Jan
(20) |
Feb
(29) |
Mar
(49) |
Apr
(89) |
May
(185) |
Jun
(131) |
Jul
(9) |
Aug
(59) |
Sep
(30) |
Oct
(44) |
Nov
(118) |
Dec
(53) |
| 2020 |
Jan
(70) |
Feb
(108) |
Mar
(50) |
Apr
(9) |
May
(70) |
Jun
(24) |
Jul
(103) |
Aug
(82) |
Sep
(132) |
Oct
(119) |
Nov
(174) |
Dec
(169) |
| 2021 |
Jan
(75) |
Feb
(51) |
Mar
(76) |
Apr
(73) |
May
(53) |
Jun
(120) |
Jul
(114) |
Aug
(73) |
Sep
(70) |
Oct
(18) |
Nov
(26) |
Dec
|
| 2022 |
Jan
(26) |
Feb
(63) |
Mar
(64) |
Apr
(64) |
May
(48) |
Jun
(74) |
Jul
(129) |
Aug
(106) |
Sep
(238) |
Oct
(169) |
Nov
(149) |
Dec
(111) |
| 2023 |
Jan
(110) |
Feb
(47) |
Mar
(82) |
Apr
(106) |
May
(168) |
Jun
(101) |
Jul
(155) |
Aug
(35) |
Sep
(51) |
Oct
(55) |
Nov
(134) |
Dec
(202) |
| 2024 |
Jan
(103) |
Feb
(129) |
Mar
(154) |
Apr
(89) |
May
(60) |
Jun
(162) |
Jul
(201) |
Aug
(61) |
Sep
(167) |
Oct
(111) |
Nov
(133) |
Dec
(141) |
| 2025 |
Jan
(122) |
Feb
(88) |
Mar
(106) |
Apr
(113) |
May
(203) |
Jun
(185) |
Jul
(124) |
Aug
(202) |
Sep
(176) |
Oct
(206) |
Nov
(259) |
Dec
(276) |
| 2026 |
Jan
(207) |
Feb
(180) |
Mar
(303) |
Apr
(309) |
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
|
From: Florent M. <flo...@gm...> - 2026-04-24 04:53:42
|
Hi Eric, my computer is more than 15 years old... You may try with the tcl there : https://github.com/florentis/tcl90-exprSH/tree/core-9-0-branch/install_SH to check with your own machine. Le 24/04/2026 à 00:11, EricT a écrit : > timerate " [Calc::transform= {} {: list(x-10,x+20,y-20,y+20) } 0 0] " > ;# 0 0 = non-proc3. > Beauty is in the eye of the beholder... This last point should be obvious. For me : % timerate {($x-10, $x+20, $y-20, $y+20)} is obviously more beautifull than : % timerate " [Calc::transform= {} {: list(x-10,x+20,y-20,y+20) } 0 0] " > There will never be a consensus on what syntax is best. A syntax is just an apparence, a shape. It's an interface to something deeper (for instance : bytecode). The goal of an interface is to make easy to work with a toolset. Command interface is well suited to work with list of strings. (Tk beauty and concision) But it is not well suited to work with numbers (operators as command are rarely used). For numbers, Tcl propose an expr interface. Why not use it ? I didn't choose the syntax in expr interface. I'm not fond of dollars signs for variable, but I accept it as it is. It is from all Tcl, as well as '[ ]' substitution. So, I don't want espacially to propose a new syntax (even if I must have one to achieve the proposal), I choosed [(y=$x;)], but it could have been also : ≺y=$x;≻ or ⎨ y =$x; ⎬ or ⟦ y = $x⟧ or ⟪ y = $x; ⟫ I want to suggest a principle. In Tcl, there is 2 parsing interfaces : * a command parsing interface, more convenient for strings and lists (using /a _prefix notation_/) * an expression parsing interface, more convenient for numbers and assignement (using /an _infix notation_/) These 2 interfaces should be of equal right, so we can choose the more convenient for a task to be done. To do so, I needed to achieve two things here : * expression substitution, to get a value from the infix parsing interface * expression script signalisation, to signal when a script must be compiled with the infix parsing interface Then, I can get the better of this two worlds. This, in less than 260 lines of code ! > There is already 4400 lines of C code in generic/tclAssembly.c that as > far as I can tell is used only to assist in the debugging of new > bytecode. > If I'm wrong, please tell me since that would provide another reason > to provide a public interface to tcl::unsupported::assemble. I have > used the Tcl assemble command to produce performance par with expr > without modification to the core. Other's could make use of a public > interface as well. Then many design specific languages (DSL) could be > built upon Tcl with high performance. Yes, Assemble bytecode is proposing its own interface, in "/_postfix notation_/". On this matter, we can adopt exactly the same principles I adopted above to resolve it. We need : * Bytecode substitution : e.g. => [! ... !] * Bytecode script signalisation : e.g. => {! ... !} set a [! load x, push 10, sub; load x, push 20, add; load y, push 20, sub; load y, push 20, add; list 4 !] proc A {} {! load x, push 10, sub load x, push 20, add load y, push 20, sub load y, push 20, add list 4 !} To achieve this, it should be very similar with as what I did for the expr shorthand, in exactly the same codes location (except the ones specific to expr, of course) * Just need a TCL_TOKEN_BYTECODE in the parser * recognize the syntax : ** in ParseCommand ** in ParseToken * route correctly the compilation int TclCompileScript. * route correctly the compilation int TclSetBytecodefromAny. * Do what it has be done with this TOKEN ** in TclSubstToken ** in TclCompileToken That's all ! This proposal is very interesting : We could even get the better of three worlds ! That said, this "/_postfix notation_/" interface is not the more convenient for the Job. As you know, /Infix notation/ is better here : set a [($x+20, $x-20, $y+20, $y-20 )] proc A {} {($x+20, $x-20, $y+20, $y-20)} At the end, you will have to create your own code to translate from your new and expr-like interface to this new bytecode interface. That is what you did. Then, this question arise : why not just have used the expr interface from the begining ? Regards, Florent |
|
From: EricT <tw...@gm...> - 2026-04-24 04:27:25
|
Serg,
Thank you again for the timerate tip. I tried to use your approach,
however, transform= cannot rewrite code inside a braced timerate block
since it's not a full tcl parser; another approach is to simply wrap
each version in its own proc and then timerate the proc calls:
proc= test {x y} {
: list(x-10,x+20,y-20,y+20)
}
proc test2 {x y} {
list [expr {$x-10}] [expr {$x+20}] [expr {$y-20}] [expr {$y+20}]
}
timerate {test 5 10}
0.450080 µs/# 2221826 # 2221826 #/sec 1000.000 net-ms
timerate {test2 5 10}
0.474814 µs/# 2106085 # 2106087 #/sec 999.999 net-ms
But perhaps the most useful comparison is simply the disassembly. Both
produce identical bytecode -- 50 instructions, 2 literal objects, same
loadScalar/push/sub/add/list sequence throughout. The only differences
are the number of command boundaries (2 vs 5) and the source text size
(175 vs 70 bytes), the latter being slightly larger in the proc=
version since the original source is preserved for debugging purposes.
The executable bytecode is identical, and timerate confirms it.
Best regards,
Eric
% tcl::unsupported::disassemble proc test
ByteCode 0x295e052dcc0, refCt 1, epoch 23, interp 0x295dc374210 (epoch 23)
Source "\nif {0} { : list(x-10,x+20,y-20,y+20) } { tcl::uns..."
Cmds 2, src 175, inst 50, litObjs 2, aux 0, stkDepth 5, code/src 0.00
Proc 0x295e05a7a60, refCt 1, args 2, compiled locals 2
slot 0, scalar, arg, "x"
slot 1, scalar, arg, "y"
Commands 2:
1: pc 0-48, src 1-172 2: pc 0-48, src 46-171
Command 1: "if {0} { : list(x-10,x+20,y-20,y+20) } { tcl::unsup..."
Command 2: "tcl::unsupported::assemble {load x; push 10; sub; load ..."
(0) loadScalar %v0 # var "x"
(5) push 0 # "10"
(10) sub
(11) loadScalar %v0 # var "x"
(16) push 1 # "20"
(21) add
(22) loadScalar %v1 # var "y"
(27) push 1 # "20"
(32) sub
(33) loadScalar %v1 # var "y"
(38) push 1 # "20"
(43) add
(44) list 4
(49) done
% tcl::unsupported::disassemble proc test2
ByteCode 0x295e053d700, refCt 1, epoch 23, interp 0x295dc374210 (epoch 23)
Source "\n list [expr {$x-10}] [expr {$x+20}] [expr {$y-20}]..."
Cmds 5, src 70, inst 50, litObjs 2, aux 0, stkDepth 5, code/src 0.00
Proc 0x295e05a88e0, refCt 1, args 2, compiled locals 2
slot 0, scalar, arg, "x"
slot 1, scalar, arg, "y"
Commands 5:
1: pc 0-48, src 5-68 2: pc 0-10, src 11-22
3: pc 11-21, src 26-37 4: pc 22-32, src 41-52
5: pc 33-43, src 56-67
Command 1: "list [expr {$x-10}] [expr {$x+20}] [expr {$y-20}] [expr..."
Command 2: "expr {$x-10}..."
(0) loadScalar %v0 # var "x"
(5) push 0 # "10"
(10) sub
Command 3: "expr {$x+20}..."
(11) loadScalar %v0 # var "x"
(16) push 1 # "20"
(21) add
Command 4: "expr {$y-20}..."
(22) loadScalar %v1 # var "y"
(27) push 1 # "20"
(32) sub
Command 5: "expr {$y+20}..."
(33) loadScalar %v1 # var "y"
(38) push 1 # "20"
(43) add
(44) list 4
(49) done
On Thu, Apr 23, 2026 at 8:48 PM EricT <tw...@gm...> wrote:
> Serg,
>
> You are correct, and thank you for the clarification. My statement was
> imprecise.
>
> The transform= function has an inproc flag that tells it whether it is
> compiling code inside a proc context or not. When inproc is true, the
> peephole optimiser generates the `load` instruction for variable access,
> which requires a proc LVT context. When inproc is false it falls back to
> `push x; loadStk` which works anywhere. The proc= compiler correctly passes
> inproc=1, but transform= could in principle also be used for toplevel code
> with inproc=0.
>
> The reason I ran timerate at the toplevel was to compare apples with
> apples since Florent's benchmarks were also at the toplevel. Your approach
> of wrapping in a proc or apply is actually more informative since it shows
> the full potential — I was not aware that timerate itself could be used
> that way and the 5x difference between toplevel and proc is striking.
>
> Best regards,
> Eric
>
> On Thu, Apr 23, 2026 at 7:12 PM Dipl. Ing. Sergey G. Brester via Tcl-Core <
> tcl...@li...> wrote:
>
>> I did not followed the whole discussion and don't want express my opinion
>> again (basically I already said everything about this and similar sugar),
>> but...
>>
>> 24.04.2026 00:11, EricT wrote:
>>
>> timerate does not work in the context of a proc.
>>
>> This assumption is definitely not correct - timerate works in the context
>> of a proc pretty well, it'd even compile better in proc or lambda frame
>> (because Tcl will compile better there).
>>
>> % set x 10; set y 20; timerate {expr {$x + $y}}
>> 0.109328 µs/# 7046239 # 9146766 #/sec 770.353 net-ms
>> % apply {{x y} { timerate {expr {$x + $y}} }} 10 20
>> 0.021571 µs/# 18462900 # 46358096 #/sec 398.267 net-ms
>> % proc test {x y} { timerate {expr {$x + $y}} }; test 10 20
>> 0.021645 µs/# 18437793 # 46200049 #/sec 399.086 net-ms
>>
>> So it'd be probably your code that doesn't work in frame properly.
>>
>> Hope this helps,
>> Serg.
>> _______________________________________________
>> Tcl-Core mailing list
>> Tcl...@li...
>> https://lists.sourceforge.net/lists/listinfo/tcl-core
>>
>
|
|
From: EricT <tw...@gm...> - 2026-04-24 03:49:20
|
Serg,
You are correct, and thank you for the clarification. My statement was
imprecise.
The transform= function has an inproc flag that tells it whether it is
compiling code inside a proc context or not. When inproc is true, the
peephole optimiser generates the `load` instruction for variable access,
which requires a proc LVT context. When inproc is false it falls back to
`push x; loadStk` which works anywhere. The proc= compiler correctly passes
inproc=1, but transform= could in principle also be used for toplevel code
with inproc=0.
The reason I ran timerate at the toplevel was to compare apples with apples
since Florent's benchmarks were also at the toplevel. Your approach of
wrapping in a proc or apply is actually more informative since it shows the
full potential — I was not aware that timerate itself could be used that
way and the 5x difference between toplevel and proc is striking.
Best regards,
Eric
On Thu, Apr 23, 2026 at 7:12 PM Dipl. Ing. Sergey G. Brester via Tcl-Core <
tcl...@li...> wrote:
> I did not followed the whole discussion and don't want express my opinion
> again (basically I already said everything about this and similar sugar),
> but...
>
> 24.04.2026 00:11, EricT wrote:
>
> timerate does not work in the context of a proc.
>
> This assumption is definitely not correct - timerate works in the context
> of a proc pretty well, it'd even compile better in proc or lambda frame
> (because Tcl will compile better there).
>
> % set x 10; set y 20; timerate {expr {$x + $y}}
> 0.109328 µs/# 7046239 # 9146766 #/sec 770.353 net-ms
> % apply {{x y} { timerate {expr {$x + $y}} }} 10 20
> 0.021571 µs/# 18462900 # 46358096 #/sec 398.267 net-ms
> % proc test {x y} { timerate {expr {$x + $y}} }; test 10 20
> 0.021645 µs/# 18437793 # 46200049 #/sec 399.086 net-ms
>
> So it'd be probably your code that doesn't work in frame properly.
>
> Hope this helps,
> Serg.
> _______________________________________________
> Tcl-Core mailing list
> Tcl...@li...
> https://lists.sourceforge.net/lists/listinfo/tcl-core
>
|
|
From: Dipl. I. S. G. B. <se...@us...> - 2026-04-24 02:11:46
|
I did not followed the whole discussion and don't want express my
opinion again (basically I already said everything about this and
similar sugar), but...
24.04.2026 00:11, EricT wrote:
> timerate does not work in the context of a proc.
This assumption is definitely not correct - timerate works in the
context of a proc pretty well, it'd even compile better in proc or
lambda frame (because Tcl will compile better there).
% set x 10; set y 20; timerate {expr {$x + $y}}
0.109328 µs/# 7046239 # 9146766 #/sec 770.353 net-ms
% apply {{x y} { timerate {expr {$x + $y}} }} 10 20
0.021571 µs/# 18462900 # 46358096 #/sec 398.267 net-ms
% proc test {x y} { timerate {expr {$x + $y}} }; test 10 20
0.021645 µs/# 18437793 # 46200049 #/sec 399.086 net-ms
So it'd be probably your code that doesn't work in frame properly.
Hope this helps,
Serg. |
|
From: Kevin W. <kw...@co...> - 2026-04-24 00:50:52
|
Hello, I am continuing to work on improving Tk's support for bidi/RTL text in the rtl_text branch. Here is the latest: 1. Users can now click through RTL text (such as Arabic or Hebrew) without the visual glitches we saw before (glyphs getting wrenched into LTR position during cursor movement). 2. Key to this was defining the following: #define TK_LAYOUT_WITH_BASE_CHUNKS 1 #define TK_DRAW_IN_CONTEXT 1 This triggered the specific blocks in Tk's text widget code that drew an entire line of text and considered that in measuring and rendering. Many of the required hooks were already present, but additional modifications of the platform-specific code (to call the platform-specific API's) and tkTextDisp.c (to provide the text widget calls) were required to support this. 3. These changes initially caused segfaults and hangs on X11 and Windows. Further modifications to tkTextDisp.c were necessary, and these required separate branches for Windows and X11 code to ensure stability on both platforms. Things are now running without crashes, in my testing. 4. Because there have been numerous updates, some of the tests in textDisp.test are now failing. There seems to be some variation across platforms. What is the best way to address this? Because the bidi text work is complex, I do not want to revert any of those updates just to ensure that a test passes. Nor do I simply want to skip the test. I would appreciate some advice on how to proceed here. 5. The final question I am looking at is whether to make bidi the default across all platforms, including X11. I had planned not to, but now that the final major issue (visual glitches in cursor movement) is close to being addressed, I am reconsidering this. I know it's getting close of the release of 9.1, but I do not see a compelling reason to NOT make bidi the default mode at this point assuming others' testing confirms stability and effectiveness. For what it's worth, Xft was added to X11 twenty-some years ago without a TIP, so I do not believe it's required here, either. Thanks for your input. - Kevin -- Kevin Walzer kw...@co... |
|
From: EricT <tw...@gm...> - 2026-04-23 22:11:38
|
Florent, Yorick, and everyone:
Florent, I'm not sure why your times are so large, my cpu is over 10
years old, but since expr is the gold standard:
% : y = (x = 3*3.14)*2 ;# command name is a single colon :
18.84
% set x
9.42
% set y
18.84
timerate { list [expr {$x-10}] [expr {$x+20}] [expr {$y-20}] [expr
{$y+20}]} ;# benchmark standard
0.439883 µs/# 2273332 # 2273332 #/sec 1000.000 net-ms
Below is when using the compiler for my : code, the first one fails
because it compiles for a proc environment, so I must specify not
inside a proc.
% timerate " [Calc::transform= {} {: list(x-10,x+20,y-20,y+20) } 1 0]
" ;# 1 0 = proc
cannot use this instruction to create a variable in a non-proc context
% timerate " [Calc::transform= {} {: list(x-10,x+20,y-20,y+20) } 0 0]
" ;# 0 0 = non-proc
0.430974 µs/# 2320322 # 2320324 #/sec 999.999 net-ms
A word of explanation.
timerate does not work in the context of a proc. My peephole optimizer
can do better inside of a proc, where the "load var;" bytecode is
permitted. Here are the outputs of the above two choices that timerate
actually tested (but one got the error):
% Calc::transform= {} {: list(x-10,x+20,y-20,y+20) } 0 0 ;# outside of a proc
tcl::unsupported::assemble {push x; loadStk; push 10; sub; push x; loadStk;
push 20; add; push y; loadStk; push 20; sub; push y; loadStk; push
20; add; list 4; }
% Calc::transform= {} {: list(x-10,x+20,y-20,y+20) } 1 0 ;# inside of a proc
tcl::unsupported::assemble {load x; push 10; sub; load x; push 20; add;
load y; push 20; sub; load y; push 20; add; list 4; }
The difference is that the peephole can fold "push x; loadStk;" ->
"load x;" which is faster but this is only permitted inside a proc
environment (or a method).
What has become apparent from our 3 proposals this last year,
$(...) jimtcl (mine)
[= ....] Colin's
[(...)] Florent's
is that all 3 are doomed because they require changes to the core.
Each requires a TIP. The difficulty with making changes to the core
are these:
1. One size does NOT fit all in Tcl
2. Performance counts
3. Beauty is in the eye of the beholder
This last point should be obvious. In Colin's = command, I prefer to
use the : character and I also prefer to have a function named "list",
rather than an empty function name as Florent's proposal.
One size does NOT fit all!
There will never be a consensus on what syntax is best. Thus there
needs to be a way to achieve performance, while allowing for different
proposals to be implemented by the users themselves - outside of the
core.
Yorick is right. It is far better to leave the core alone and code in
pure tcl. However, as was discussed in the last telco,
The machinery to extend the language should improve.
-> there is no interface to bytecode extension.
-> due to that missing, "=" must go to the core.
-> C invocation from the bytecode compiler is slow.
However, the answer is in plain sight:
There is already 4400 lines of C code in generic/tclAssembly.c that as
far as I can tell is used only to assist in the debugging of new
bytecode. If I'm wrong, please tell me since that would provide
another reason to provide a public interface to
tcl::unsupported::assemble.
I have used the Tcl assemble command to produce performance par with
expr without modification to the core. Other's could make use of a
public interface as well. Then many design specific languages (DSL)
could be built upon Tcl with high performance.
As always, I want to thank Colin for his fine work, both his C code
and his pure tcl prototype which I have built my compiler on, which
can be found here:
https://github.com/rocketship88/colin-parser
Eric
On Thu, Apr 23, 2026 at 1:07 PM Florent Merlet <flo...@gm...>
wrote:
> Hi Rene,
> There begins to be a lot of commands into the core.
>
> Every new release, new commands appears.
> Is the memory of people infinite, so they can learn a continuous
> extending set of commands ?
>
> The problem is : How do we interface command with math calculation ?
>
> There is many possibilities :
> * we expect to make a calculation and return the result (expr)
> * we expect to make calculation and return no result, just make a side
> effect somewhere in the interpreter (???)
> * we expect a to produce list of calculations (lexpr)
> * we expect to set a list of vars from calculations (let)
> * we expect to apply expr to each elements of a list (foreach / lmap +
> expr)
> * ...
>
> Are you sure that to have one command for each possibility is the viable
> solution ?
> What about the inflation of command names in the command Table ?
>
> With my proposal, you can get all this without any new command beeing
> added anywhere.
> set L [(1,2,3,4)] ; # set a list
> [(a=1; b=3; c=3;)]; # set as many variables as you want
>
> You can even set a list, while setting individual element to a value. Ex :
>
> % [(P = (x=1, y=2, z=3) ;)]
> 1 2 3
> (bin) 41 % set x
> 1
> (bin) 42 % set y
> 2
> (bin) 43 % set z
> 3
> (bin) 44 % set P
> 1 2 3
>
> What would be the name of this last command for you ? ellexpr ? lelexpr ?
>
> You may also choose to set a matrix, record its rows in an array, and
> set its individuals elements to variable
>
> [( M = (
> "row(0)" = (a = 1, b = 2, c = 3),
> "row(1)" = (d = 4, e = 5, f = 6),
> "row(2)" = (g = 7, h = 8, i = 9)
> )
> ;)]
>
> (bin) 51 % set M
> {1 2 3} {4 5 6} {7 8 9}
> (bin) 52 % set row(0)
> 1 2 3
> (bin) 53 % set row(1)
> 4 5 6
> (bin) 54 % set row(2)
> 7 8 9
> (bin) 55 % list $a $b $c $d $e $f $g $h $i
> 1 2 3 4 5 6 7 8 9
>
> What would be the name of this last command for you ? elArrMAtexpr ?
> MatArraelexpr ?
>
> How many lines to get this effect with the command interface ?
> I think we can quickly get a limit.
>
> The command interface is very good for some think, very efficient.
> For some other things, it is too poor.
>
> I will never use an expr-like syntax for widget, or strings lists, or dicts
> But why insisting to use command-like syntax for calculation ?
> expr is allready there. Why not just use it in its full capabilities ?
>
> Try this (on windows, static compiled with mingwin)
>
> https://github.com/florentis/tcl90-exprSH/tree/core-9-0-branch/install_SH
>
> Regards,
> Florent
>
> Le 23/04/2026 à 16:15, Zaumseil René via Tcl-Core a écrit :
> > Hello Yorick
> >
> > Very cool. It reminds me of my own "let" proposal.
> > Imho these 2 functions should go at least in the ::tcl namespace.
> > The big problem is to find proper names.
> >
> > For the first "= {..} {..}" I would propose "tcl::lexpr ..
> > For the second "= x .. y.." I would propose "tcl::let .."
> >
> > This is like TIP 760.
> >
> > Thank you
> > rene
> >
> >
> > -----Ursprüngliche Nachricht-----
> > Von: Poor Yorick <org...@po...>
> > Gesendet: Donnerstag, 23. April 2026 11:36
> > An: tcl...@li...
> > Betreff: [Ext] Re: [TCLCORE] TIP 676 results - doesn't pass
> >
> > On 2026-04-23 11:28, EricT wrote:
> >> Hi Poor,
> >>
> >> Can you elaborate on your = helper here?
> >>
> >> Is this something that takes each argument and passes it on to expr,
> >> and then returns a list of results? If so, can you pass it to expr
> >> braced so it compiles efficiently?
> >>
> >> Regards,
> >>
> >> Eric
> > Here is it is:
> >
> > proc = args {
> > lmap item $args[set args {}] {uplevel 1 [list ::expr
> $item]}
> > }
> >
> > Example:
> >
> > .canvas addtag enclosed {*}[= {$x-20} {$x+20} {$y-20} {$y+20}]
> >
> >
> > If that isn't efficient enough, then making the necessary to changes to
> Tcl to make it more efficient would be a good direction.
> >
> > But I would call that something like lexpr so that = could be used to
> make expr more convenient:
> >
> > proc = args {
> > uplevel 1 [join [lmap {varname expr} $args[set args {}] {
> > lindex "::set [list $varname] \[::expr [list
> $expr]]"
> > }] \n]
> > }
> >
> > Example:
> >
> > = x {3 * 3.14} y {$x * 2}
> >
> > Those two procedures make doing math in Tcl pretty reasonable, without
> any language modification.
> >
> > --
> > Yorick
> >
> >
> > _______________________________________________
> > Tcl-Core mailing list
> > Tcl...@li...
> > https://lists.sourceforge.net/lists/listinfo/tcl-core
> >
> >
> > _______________________________________________
> > Tcl-Core mailing list
> > Tcl...@li...
> > https://lists.sourceforge.net/lists/listinfo/tcl-core
>
> --
> <center>
> <hr/>
> <b>Florent MERLET</b><br/>
> <i>4 rue Johann Strauss<br/>
> Logement 7<br/>
> 86180 BUXEROLLES</i><br/>
> <hr/>
> <b>Mél.</b> : <i>flo...@gm...</i><br/>
> <b>Tél.</b> : <i>06 70 00 63 48</i>
> </center>
>
>
>
>
> _______________________________________________
> Tcl-Core mailing list
> Tcl...@li...
> https://lists.sourceforge.net/lists/listinfo/tcl-core
>
|
|
From: Florent M. <flo...@gm...> - 2026-04-23 20:07:44
|
Hi Rene,
There begins to be a lot of commands into the core.
Every new release, new commands appears.
Is the memory of people infinite, so they can learn a continuous
extending set of commands ?
The problem is : How do we interface command with math calculation ?
There is many possibilities :
* we expect to make a calculation and return the result (expr)
* we expect to make calculation and return no result, just make a side
effect somewhere in the interpreter (???)
* we expect a to produce list of calculations (lexpr)
* we expect to set a list of vars from calculations (let)
* we expect to apply expr to each elements of a list (foreach / lmap +
expr)
* ...
Are you sure that to have one command for each possibility is the viable
solution ?
What about the inflation of command names in the command Table ?
With my proposal, you can get all this without any new command beeing
added anywhere.
set L [(1,2,3,4)] ; # set a list
[(a=1; b=3; c=3;)]; # set as many variables as you want
You can even set a list, while setting individual element to a value. Ex :
% [(P = (x=1, y=2, z=3) ;)]
1 2 3
(bin) 41 % set x
1
(bin) 42 % set y
2
(bin) 43 % set z
3
(bin) 44 % set P
1 2 3
What would be the name of this last command for you ? ellexpr ? lelexpr ?
You may also choose to set a matrix, record its rows in an array, and
set its individuals elements to variable
[( M = (
"row(0)" = (a = 1, b = 2, c = 3),
"row(1)" = (d = 4, e = 5, f = 6),
"row(2)" = (g = 7, h = 8, i = 9)
)
;)]
(bin) 51 % set M
{1 2 3} {4 5 6} {7 8 9}
(bin) 52 % set row(0)
1 2 3
(bin) 53 % set row(1)
4 5 6
(bin) 54 % set row(2)
7 8 9
(bin) 55 % list $a $b $c $d $e $f $g $h $i
1 2 3 4 5 6 7 8 9
What would be the name of this last command for you ? elArrMAtexpr ?
MatArraelexpr ?
How many lines to get this effect with the command interface ?
I think we can quickly get a limit.
The command interface is very good for some think, very efficient.
For some other things, it is too poor.
I will never use an expr-like syntax for widget, or strings lists, or dicts
But why insisting to use command-like syntax for calculation ?
expr is allready there. Why not just use it in its full capabilities ?
Try this (on windows, static compiled with mingwin)
https://github.com/florentis/tcl90-exprSH/tree/core-9-0-branch/install_SH
Regards,
Florent
Le 23/04/2026 à 16:15, Zaumseil René via Tcl-Core a écrit :
> Hello Yorick
>
> Very cool. It reminds me of my own "let" proposal.
> Imho these 2 functions should go at least in the ::tcl namespace.
> The big problem is to find proper names.
>
> For the first "= {..} {..}" I would propose "tcl::lexpr ..
> For the second "= x .. y.." I would propose "tcl::let .."
>
> This is like TIP 760.
>
> Thank you
> rene
>
>
> -----Ursprüngliche Nachricht-----
> Von: Poor Yorick <org...@po...>
> Gesendet: Donnerstag, 23. April 2026 11:36
> An: tcl...@li...
> Betreff: [Ext] Re: [TCLCORE] TIP 676 results - doesn't pass
>
> On 2026-04-23 11:28, EricT wrote:
>> Hi Poor,
>>
>> Can you elaborate on your = helper here?
>>
>> Is this something that takes each argument and passes it on to expr,
>> and then returns a list of results? If so, can you pass it to expr
>> braced so it compiles efficiently?
>>
>> Regards,
>>
>> Eric
> Here is it is:
>
> proc = args {
> lmap item $args[set args {}] {uplevel 1 [list ::expr $item]}
> }
>
> Example:
>
> .canvas addtag enclosed {*}[= {$x-20} {$x+20} {$y-20} {$y+20}]
>
>
> If that isn't efficient enough, then making the necessary to changes to Tcl to make it more efficient would be a good direction.
>
> But I would call that something like lexpr so that = could be used to make expr more convenient:
>
> proc = args {
> uplevel 1 [join [lmap {varname expr} $args[set args {}] {
> lindex "::set [list $varname] \[::expr [list $expr]]"
> }] \n]
> }
>
> Example:
>
> = x {3 * 3.14} y {$x * 2}
>
> Those two procedures make doing math in Tcl pretty reasonable, without any language modification.
>
> --
> Yorick
>
>
> _______________________________________________
> Tcl-Core mailing list
> Tcl...@li...
> https://lists.sourceforge.net/lists/listinfo/tcl-core
>
>
> _______________________________________________
> Tcl-Core mailing list
> Tcl...@li...
> https://lists.sourceforge.net/lists/listinfo/tcl-core
--
<center>
<hr/>
<b>Florent MERLET</b><br/>
<i>4 rue Johann Strauss<br/>
Logement 7<br/>
86180 BUXEROLLES</i><br/>
<hr/>
<b>Mél.</b> : <i>flo...@gm...</i><br/>
<b>Tél.</b> : <i>06 70 00 63 48</i>
</center>
|
|
From: Florent M. <flo...@gm...> - 2026-04-23 19:57:52
|
Hi Eric, Hi Yoric, Hi all,
Here the result I get for it :
(bin) 70 % timerate {
set x [expr {3*3.14}]; set y [expr {$x*2}]
}
1.191671 µs/# 839156 # 839157 #/sec 999.998 net-ms
(bin) 71 % timerate {(
y = (x = 3*3.14)*2
)}
1.180498 µs/# 847099 # 847099 #/sec 999.999 net-ms
(bin) 72 % timerate {
list [expr {$x-10}] [expr {$x+20}] [expr {$y-20}] [expr {$y+20}]
}
2.816785 µs/# 355014 # 355014 #/sec 999.998 net-ms
(bin) 73 % timerate {(
$x-10, $x+20, $y-20, $y+20
)}
2.844616 µs/# 351541 # 351541 #/sec 999.999 net-ms
Shorter, more readable, as fast as the original !
Just check there :
https://github.com/florentis/tcl90-exprSH/tree/core-9-0-branch/install_SH
Regards,
Florent
Le 23/04/2026 à 17:33, EricT a écrit :
> Hi Yorik,
>
> Thanks for those 2 procedures.
>
> The first one compared to code using braced expr has about a 4.5x
> performance decrease.
>
> However, the second example, was quite more, there I found a 40x decrease.
>
> Do you find the same results?
>
> Eric
>
>
>
>
> On Thu, Apr 23, 2026 at 7:30 AM Zaumseil René via Tcl-Core
> <tcl...@li...> wrote:
>
> Hello Yorick
>
> Very cool. It reminds me of my own "let" proposal.
> Imho these 2 functions should go at least in the ::tcl namespace.
> The big problem is to find proper names.
>
> For the first "= {..} {..}" I would propose "tcl::lexpr ..
> For the second "= x .. y.." I would propose "tcl::let .."
>
> This is like TIP 760.
>
> Thank you
> rene
>
>
> -----Ursprüngliche Nachricht-----
> Von: Poor Yorick <org...@po...>
> Gesendet: Donnerstag, 23. April 2026 11:36
> An: tcl...@li...
> Betreff: [Ext] Re: [TCLCORE] TIP 676 results - doesn't pass
>
> On 2026-04-23 11:28, EricT wrote:
> > Hi Poor,
> >
> > Can you elaborate on your = helper here?
> >
> > Is this something that takes each argument and passes it on to
> expr,
> > and then returns a list of results? If so, can you pass it to expr
> > braced so it compiles efficiently?
> >
> > Regards,
> >
> > Eric
>
> Here is it is:
>
> proc = args {
> lmap item $args[set args {}] {uplevel 1 [list
> ::expr $item]}
> }
>
> Example:
>
> .canvas addtag enclosed {*}[= {$x-20} {$x+20} {$y-20} {$y+20}]
>
>
> If that isn't efficient enough, then making the necessary to
> changes to Tcl to make it more efficient would be a good direction.
>
> But I would call that something like lexpr so that = could be used
> to make expr more convenient:
>
> proc = args {
> uplevel 1 [join [lmap {varname expr} $args[set
> args {}] {
> lindex "::set [list $varname] \[::expr
> [list $expr]]"
> }] \n]
> }
>
> Example:
>
> = x {3 * 3.14} y {$x * 2}
>
> Those two procedures make doing math in Tcl pretty reasonable,
> without any language modification.
>
> --
> Yorick
>
>
> _______________________________________________
> Tcl-Core mailing list
> Tcl...@li...
> https://lists.sourceforge.net/lists/listinfo/tcl-core
>
>
> _______________________________________________
> Tcl-Core mailing list
> Tcl...@li...
> https://lists.sourceforge.net/lists/listinfo/tcl-core
>
>
>
> _______________________________________________
> Tcl-Core mailing list
> Tcl...@li...
> https://lists.sourceforge.net/lists/listinfo/tcl-core |
|
From: Mason M. <ma...@ba...> - 2026-04-23 19:34:01
|
Florent, I will give it a try! You got me thinking now, with Unicode support widespread, what would it take to add another built-in delimiter like “[“ and “]” but more mathematically oriented like: ⟦x^2 + 2*x + 4⟧ Instead of having a procedure defined it would be a built-in. This would potentially provide the cleanest delimiter that wouldn’t clash with any others because it is distinct. It would also be potentially the cleanest with less symbols and visual weight even in the short expressions: lappend X ⟦x + 2⟧ ⟦y * 10⟧ I like the concept of the = operator as is shown in the Expression shorthand but it seems this might be cleaner even though it probably will be more C code underneath. Mason On Thu, Apr 23, 2026, at 1:03 PM, Florent Merlet wrote: > Hi Mason, > > I also prefer to give name to the things. It is always more readable than obscure syntax chars. > > That's why, to take your example, I will write it like this : > > [( ycoord = $y + 5; zcoord = $z * 10; )] > > lappend X $ycoord $zcoord > > Despite the unnecessary spaces I added for clarity, what I wrote is only 68 chars, what is 23 chars less than you example (16 % less). > And it is not less readable. > > Don't forget : it includes TIP 282, List capabilities, and "Muting inline expression" (thanks to the trailing semi-colon), so you can reduce the number of '[( ... )]'. > You can group many calculation in between. > > Try it there : https://github.com/florentis/tcl90-exprSH/tree/core-9-0-branch/install_SH > > Regards > Florent > Le 23/04/2026 à 17:09, Mason McParlane a écrit : >> Terseness does not improve readability. Programming is 80% reading 20% writing. Just throwing those numbers there's no science behind it but I'm sure everyone has felt the impact of reading other people's code. It is difficult to get into the minds of others. I say that because, regardless of how easy or difficult a change might be to implement, or how useful it might be for some, to put something in the core that encourages people to write non-idiomatic code can be problematic. By that I mean, variables without sigils; cryptic commands like "(" and ")" which belong in the realm of lisp. >> >> Here is some facts why this doesn't work well, based on the Gestalt theory of grouping (https://en.wikipedia.org/wiki/Principles_of_grouping). The following is very difficult to read because the "[(" and ")]" has more visual weight than the expression itself. Having the "expr" word helps soften the visual weight of brackets in close proximity. >> >> lappend X [($y+5)] [($z*10)]; >> >> While it seems easier to write, and perhaps it is, it is much more difficult to read than: >> >> set ycoord [expr {$y + 5}] >> set zcoord [expr {$z * 10}] >> lappend X $ycoord $zcoord >> >> I realize that the intent is probably for more complex expressions than those examples, but this hopefully shows that there is a serious downside to having these in the core when it comes to readability. >> >> >> Mason >> >> >> >> On Thu, Apr 23, 2026, at 10:40 AM, Florent Merlet wrote: >>> Hi Martin, Peter, Community, >>> >>> Code impact is only 259 lines of code. >>> 2 enums , 4 C-array updated, 11 functions modified, in 4 files. >>> >>> It is not much. It's not immense as you assert. >>> It's very little for the effect ! >>> >>> Here is a summary of the changes : >>> >>> kind / part Subst Script TIP282 List Total (kind) >>> new lines 75 55 51 24 205 >>> line changed 1 0 2 2 5 >>> line space / comment 15 13 13 8 49 >>> Total (part) 91 68 66 34 259 >>> >>> NB : Each "part" is one part of the Proposal : >>> * Subst is for '[( ... )]' shorthand expression substitution >>> * Script is for script substitution (ex : eval (1+1) ; proc P {} {( ... )}; if {...} then (0) else "($res)" ; ...etc) >>> * TIP 282 is for SEPARATOR and ASSIGNEMENT : 'expr {a = 1; b = 2}' >>> * List is for list handling : 'expr {(1, 2, 3, 4)}' >>> >>> You'll find an Excel File in attachement for more details. >>> >>> [ Notice that I removed the most problematic part (substitution of array index) : >>> It appears that an index can be parsed in the middle of execution. As to compute an index with expr, I needed to compile bytecodes, it was not doable.] >>> >>> I respect your opinion, but, I think you didn't try the implementation. >>> There may be some misunderstanding. >>> >>> Myself, I could load a big package tcllib::math, nothing was complaining. >>> Of course, lot of tests have to be made. >>> >>> I recieved opinions, more encouraging than yours : >>> >>> AMB wrote in the Wiki yesterday (ref https://wiki.tcl-lang.org/page/A+Better+way+to+do+calculations) >>> -------------------------------------------------- >>> *AMB <https://wiki.tcl-lang.org/page/AMB> - 2026-04-22 19:47:30* >>> I downloaded your prototype, FM <https://wiki.tcl-lang.org/page/FM>, and it's great!! >>> >>> ----------------------------------------------------------------- >>> >>> Ok, he would like to allow spaces before and after the parentheses. We could use Tcl_ParseWhiteSpace for this, but It must be discussed. >>> I prefer to have something that look like a two-char symbol `[(` `{(` `"(`. But, in console context, why not ? >>> >>> Whatever. Now there is a prototype. >>> Before any new change, it's better everybody can play with this prototype and comment it. >>> My time is counted also, that's why I count on the community feedback. >>> >>> I 'm proposing you to try the prototype first (for windows, statically compiled with gcc, under mingwin). >>> You'll find it at : https://github.com/florentis/tcl90-exprSH/tree/core-9-0-branch/install_SH >>> >>> The actual version of the TIP text, which must be improved, can be found at : >>> https://github.com/florentis/tcl90-exprSH/blob/core-9-0-branch/TIP_Expr_Shorthand.md >>> >>> Then you can give an opinion founded on facts, not on what it may be, at the view of a long mailing list discussion. >>> >>> Regards, Tchüss, >>> >>> Florent >>> >>> >>> Le 22/04/2026 à 23:27, Martin Lemburg a écrit : >>>> Reading all the content provided by you, Florent, my gut feeling about not wanting those changes gets louder, stronger. >>>> >>>> The changes let us win some simplicity in using mathmatics everywhere. >>>> The costs are imense, since basic things changes like you just described. >>>> >>>> Additionally, the costs of changes in several parts of the tcl sources and probably introduced bugs (no one develops in a complex environment without introducing bugs) encourage my gut to shake his head, mourning "no, no, no". >>>> >>>> To introduce a new command with a "new" little language only for mathmathics is one (quite discussable) thing - not changing parts of tcl parser. >>>> The changes you propose are much wider/deeper in their consequences and the longer I think of them the more I think, that they are too risky and that they go too far. >>>> >>>> Best regards >>>> >>>> Martin Lemburg >>>> Berlin / Germany >>>> >>>> mar...@gm... >>>> *Gesendet: *Mittwoch, 22. April 2026 um 22:19 >>>> *Von: *"Florent Merlet" <flo...@gm...> >>>> *An: *"da Silva, Peter J" <pet...@fl...>, "tcl...@li..." <tcl...@li...> >>>> *Betreff: *Re: [TCLCORE] Variation on the Expr Shorthand >>>> Le 22/04/2026 à 16:50, da Silva, Peter J a écrit : >>>>> OK: >>>>> >>>>> % proc ( {args} { puts "( $args" } >>>>> % ( hello ) >>>>> ( hello ) >>>>> >>>>> This is legal existing syntax. >>>>> >>>> Hi Peter, >>>> >>>> It's still legal, but the meaning is different : it makes '(' a meaningfull symbol in some context. >>>> >>>> If you want a '(' proc, it would then be like it is now with '[' proc, '{' proc or {"} proc : >>>> You would have to protect it with backslah when you call it. >>>> Like it is now : >>>> >>>> % \( hello ) >>>> ( hello ) >>>> % set a [\( hello )] >>>> ( hello ) >>>> % proc A {} {\( hello )} >>>> % A >>>> ( hello ) >>>> >>>> There is clearly a choice to be made. >>>> >>>> Is it acceptable to be forced to add an extra backslah to call the "(" proc, >>>> just to gain at least 4 chars for each expression used in a script ? >>>> >>>> My opinion is "yes", it is very acceptable, because I never use any "(" proc, and because I'm fade up writing things like : >>>> >>>> set a [expr {...}] >>>> set b [expr {...}] >>>> >>>> Without hesitation, I prefer to write : >>>> >>>> [(a = ...; b = ...;)] >>>> >>>> Even in including some non essential whitespace for clarity, the last is only 21 chars, whereas the first is 36 chars. >>>> So, I can still call the "(" proc 15 times, whithout any loss. >>>> >>>> My deep opinion is even it would be unacceptable to not accept it. >>>> >>>> But I would understand it exists other opinions. >>>> >>>> Regards >>>>> >>>>> >>>>> *From: *Florent Merlet <flo...@gm...> >>>>> *Date: *Wednesday, April 22, 2026 at 06:41 >>>>> *To: *da Silva, Peter J (USA) <pet...@fl...>; tcl...@li... <tcl...@li...> >>>>> *Subject: *Re: [TCLCORE] Variation on the Expr Shorthand >>>>> CAUTION - EXTERNAL EMAIL: >>>>> This message originated from outside of your organization. Do not click links or open attachments unless you recognize the sender and know the content is safe. >>>>> >>>>> Le 29/10/2025 à 15:56, da Silva, Peter J a écrit : >>>>>> That has the same problem of breaking existing syntax. >>>>>> >>>>>> % proc ( {args} { puts $args } >>>>>> % ( hello >>>>>> hello >>>>> >>>>> Hi Peter, >>>>> >>>>> No, It doesn't : check -> https://github.com/florentis/tcl90-exprSH/tree/core-9-0-branch/install_SH/bin <https://urldefense.us/v2/url?u=https-3A__github.com_florentis_tcl90-2DexprSH_tree_core-2D9-2D0-2Dbranch_install-5FSH_bin&d=DwMDaQ&c=MASr1KIcYm9UGIT-jfIzwQg1YBeAkaJoBtxV_4o83uQ&r=BRyGRggIJd8TmKOhvEmGElFuDuCl3O5mT8opva3f-Uc&m=w2tfEZJ11k3zrwJuBQ24gT2PBdBoy0rWTxoFVW7mf-Wmbu-TPHMsSUmUoCydsS8B&s=TQbNb_jQH5uxu4bjbvHKXOCChssskqh-ohkPZULZRnI&e=> >>>>> >>>>> I) In *console wish context* : >>>>> a) No closed paren -> _proc_ >>>>> (bin) 4 % ( hello >>>>> hello >>>>> -> ie : The last argument must finish with a ')' >>>>> >>>>> b) First char = open paren, last char = closed paren -> _expression_ >>>>> 5 % ( hello ) >>>>> invalid bareword "hello" >>>>> in expression "( hello ) >>>>> "; >>>>> should be "$hello" or "{hello}" or "hello(...)" or ... >>>>> >>>>> -> If ever, add a space before the open parenthese or after the close parenthese. >>>>> >>>>> c) First char = open paren, last char = space -> _proc_ >>>>> 6 % ( hello ) ; >>>>> hello >>>>> >>>>> d) First char = space, last char = close paren -> _proc_ >>>>> 7 % ( hello ) >>>>> hello ) >>>>> >>>>> II) In *script context*, it's also true : >>>>> a) No closed paren >>>>> (bin) 8 % proc A {} {( hello} >>>>> (bin) 9 % A >>>>> hello >>>>> b) First char = open paren, last char = closed paren -> _expression_ >>>>> (bin) 10 % proc B {} {( hello )} >>>>> (bin) 11 % B >>>>> invalid bareword "hello" >>>>> in expression "( hello )"; >>>>> should be "$hello" or "{hello}" or "hello(...)" or ... >>>>> >>>>> c) First char = open paren, last char = space -> _proc_ >>>>> (bin) 12 % proc C {} {( hello ) } >>>>> (bin) 13 % C >>>>> hello ) >>>>> >>>>> d) First char = space, last char = closed paren -> _proc_ >>>>> (bin) 14 % proc D {} { ( hello)} >>>>> (bin) 15 % D >>>>> hello) >>>>> >>>>> III) In *substitution context*, I have to implement it when coming back from expr with parsing error, to get the same effect. >>>>> I think it's doable. >>>>> >>>>> a) No closed paren : -> expression* (to be corrected, should be proc)* >>>>> (bin) 16 % set A [( hello ] >>>>> invalid bareword "hello" >>>>> in expression "( hello ] >>>>> "; >>>>> should be "$hello" or "{hello}" or "hello(...)" or ... >>>>> >>>>> b) first char = open paren, last char = close paren -> expression. >>>>> (bin) 17 % set B [( hello )] >>>>> invalid bareword "hello" >>>>> in expression "( hello )] >>>>> "; >>>>> should be "$hello" or "{hello}" or "hello(...)" or ... >>>>> >>>>> c) First char = space, , last char = close paren -> proc >>>>> (bin) 18 % set C [ ( hello )] >>>>> hello ) >>>>> >>>>> d) first char = open paren, last char = space -> expression *(to be corrected, should be proc)* >>>>> (bin) 16 % set D [( hello ) ] >>>>> invalid bareword "hello" >>>>> in expression "( hello ) ] >>>>> "; >>>>> should be "$hello" or "{hello}" or "hello(...)" or ... >>>>> >>>>> Regards >>>>> >>>>>> >>>>>> *From: *Florent Merlet <flo...@gm...> >>>>>> *Date: *Wednesday, October 29, 2025 at 09:45 >>>>>> *To: *tcl...@li... <tcl...@li...> >>>>>> *Subject: *[TCLCORE] Variation on the Expr Shorthand >>>>>> CAUTION - EXTERNAL EMAIL: >>>>>> This message originated from outside of your organization. Do not click links or open attachments unless you recognize the sender and know the content is safe. >>>>>> >>>>>> Hi dear Tcl community, >>>>>> >>>>>> An Expr shorthand syntax has been a long time demand between us. >>>>>> >>>>>> Those discussions always focus on the syntax aspect of the subject : >>>>>> >>>>>> • Like in bash $(...) or $((...)) >>>>>> • Through an alias [= ...] >>>>>> • A new command (vexpr or let) >>>>>> • A word prefix {=} >>>>>> • ... >>>>>> A lot of TIPs exists on that matter. Numerous discussions occurs, which never ended to get a consensus. >>>>>> >>>>>> That's because the look of this shorthand is a matter of taste. Everybody has his own taste. Some people like fish when it's cooked in water, some people like it when it's fried. Some people even don't like fish at all ! Every taste is in the nature. >>>>>> >>>>>> Everybody can agree that Tcl is a big and complex machinery, that must be handled with care. So maybe the problem must be taken the other way round : >>>>>> >>>>>> • Shall we deduce the Tcl C source code machinery from a new syntax, we had previously decided (the one doesn't make consensus) >>>>>> • Or shall we deduce the new syntax from the Tcl C source code machinery, as it exists ? >>>>>> My opinion is that it's better to deduce the syntax from the Tcl C source code, rather than to deduce the Tcl source C code from the syntax . >>>>>> >>>>>> TIP 672 is hacking the variable substitution. To do this, it has to make a very basic parsing of the expression to estimate its length. It has to transmute a TCL_VARIABLE Token into a TCL_COMMAND token. It then use a call to Tcl_ParseCommand on a synthetic string to check errors. >>>>>> >>>>>> This very basic parsing will make it buggy. For instance, a shorthand expression can't be nested in another one. A quote inside braces would create an error. To make this parsing strong, we would have to reinvent all the expression parsing from scratch. >>>>>> >>>>>> But shall we create a new parsing expression routine for this shorthand ? No, there exist already an expression parsing machinery, that can handle words between Quotes or Braces and can handle Nested Commands, exactly how the Expr command do. >>>>>> >>>>>> « Deduce the shorthand syntax from the Tcl C source Code » imply to find a syntax which allows us to use the existing machinery. >>>>>> >>>>>> That's what I'm trying now : >>>>>> >>>>>> As Expr is a command in Tcl, it seems logical to me to implement the shorthand syntax in the Command branch "[" of parseToken procedure. That's what I choosed. >>>>>> >>>>>> The second step is to parse the expression, so to go through Tcl_ParseExpr routine, then to the ParseExpr routine. The difficulty here is to get the end of the substitution script in the ParseExpr routine. If I don't want to disturb parseExpr too much, it's better to choose, as character which ends the expression script, a character that is significant for this parser, so the main task of detecting it is already done, but can be adapted gently. >>>>>> >>>>>> Maybe I could have used any of those operators : '+', '=', '-', '*', '(', ')', '|',...etc. But I choosed to use ')' : infix language needs parenthesis. >>>>>> >>>>>> That is how I defined the end of the expression substitution script to be ")]". By symetry, I defined the beginning of the substitution script to be "[(". >>>>>> >>>>>> Here is the genesis of my proposal of "[( ...)]" as a shorthand. >>>>>> >>>>>> To make it work, I had to used the same clever hacking than Eric Taylor : create a synthethic string and parse it as a command. >>>>>> >>>>>> At the end, the [(...)] is working as expected (so far I've tested). Here are the main changes I have done to accomplish it : >>>>>> >>>>>> In file Tcl_Parse.c : in function parseTokens, I add a new branch in the test >>>>>> >>>>>> ---------------------------------------- >>>>>> >>>>>> ... } else if (src[0] == '[' && src[1] == '(') { >>>>>> /////////////////////////////////////////////////////////////////////// >>>>>> /* Expression substition context */ >>>>>> // to do : noSubstExpr >>>>>> Tcl_Parse *exprParsePtr; >>>>>> exprParsePtr =(Tcl_Parse *)TclStackAlloc(parsePtr->interp, sizeof(Tcl_Parse)); >>>>>> >>>>>> src++; // src == '[' >>>>>> numBytes --; >>>>>> // Use it only to know the length of the expression, and store it into exprParsePtr->commandSize >>>>>> Tcl_ParseExpr(parsePtr->interp, src, numBytes, exprParsePtr); >>>>>> >>>>>> src++; // src == '(' >>>>>> numBytes --; >>>>>> >>>>>> // Here is the famous hack of Eric Taylor >>>>>> Tcl_Size syntheticLen = exprParsePtr->commandSize + 9; // "[expr {" + expr + "}]" >>>>>> >>>>>> char *synthetic = (char *)Tcl_Alloc(syntheticLen + 1); >>>>>> >>>>>> memcpy(synthetic, "[expr {", 7); >>>>>> memcpy(synthetic + 7, src, exprParsePtr->commandSize); >>>>>> >>>>>> memcpy(synthetic + 7 + exprParsePtr->commandSize, "}]", 3); >>>>>> synthetic[syntheticLen] = '\0'; >>>>>> // Maybe a Tcl_Obj could be of use for memory management ? >>>>>> >>>>>> Tcl_Obj *exprObjCommand = Tcl_NewStringObj(synthetic,syntheticLen); >>>>>> >>>>>> src+=exprParsePtr->commandSize+2; >>>>>> numBytes-=exprParsePtr->commandSize+2; >>>>>> >>>>>> TclStackFree(parsePtr->interp, exprParsePtr); >>>>>> >>>>>> tokenPtr->type = TCL_TOKEN_COMMAND; >>>>>> tokenPtr->start = Tcl_GetStringFromObj(exprObjCommand, NULL); >>>>>> tokenPtr->size = syntheticLen; >>>>>> parsePtr->numTokens++; >>>>>> >>>>>> continue; >>>>>> >>>>>> } else if (*src == '[') {... >>>>>> >>>>>> --------------------------------------- >>>>>> >>>>>> To detect the end and transfer the size of the parsed expression I had to modify : >>>>>> >>>>>> 1° the Tcl_ParseExpr function : >>>>>> >>>>>> ... if (code == TCL_OK) { >>>>>> if(start[-1] == '[' && start[0] == '(' ) { >>>>>> // Expression Substitution Context : just transfer the size information to the caller >>>>>> parsePtr->commandSize =exprParsePtr->commandSize; >>>>>> } else { >>>>>> TclParseInit(interp, start, numBytes, parsePtr); >>>>>> ConvertTreeToTokens(start, numBytes, >>>>>> opTree, exprParsePtr->tokenPtr, parsePtr); >>>>>> } ... >>>>>> >>>>>> 2° the ParseExpr fonction >>>>>> >>>>>> int nb_paren=0; >>>>>> int substExpressionContext=0; >>>>>> >>>>>> if(start[-1] == '[' && start[0] == '(' ) { >>>>>> substExpressionContext=1; >>>>>> >>>>>> // Expression substitution >>>>>> start++; //skip the open parenthesis '(' : it's part of the expression substitution syntax >>>>>> numBytes--; >>>>>> } >>>>>> >>>>>> ... >>>>>> >>>>>> case UNARY: >>>>>> >>>>>> ////////////////////////////////// >>>>>> >>>>>> if (substExpressionContext == 1) { >>>>>> >>>>>> // Beyond binary operators, there is Open paren, count it >>>>>> >>>>>> if (start[0]== '(') { >>>>>> >>>>>> // Count the open parenthesis in this context >>>>>> >>>>>> nb_paren++; >>>>>> } >>>>>> } >>>>>> >>>>>> case BINARY: { >>>>>> ... >>>>>> if (substExpressionContext == 1) { >>>>>> >>>>>> // Beyond binary operators, there is closed Paren, count it. >>>>>> >>>>>> if (start[0] == ')') { >>>>>> nb_paren--; >>>>>> if (nb_paren == -1 && start[1] ==']') { >>>>>> //// End of expression >>>>>> parsePtr->commandSize = originalLength - numBytes - 1; >>>>>> numBytes=0; >>>>>> continue; // and exit the loop, since numbytes == 0 ;) >>>>>> } >>>>>> } >>>>>> } >>>>>> >>>>>> ---------------------------------------- >>>>>> >>>>>> I add also make it nestable, ie : set x [(1 + [(2+3)] )] >>>>>> >>>>>> in the function Parse_Expr : >>>>>> >>>>>> case SCRIPT : { >>>>>> >>>>>> ... >>>>>> >>>>>> if (start[1] == '(') { >>>>>> >>>>>> // an open braket followed by an open paren is denoting the expression shorthand >>>>>> >>>>>> tokenPtr->type = TCL_TOKEN_SUB_EXPR; >>>>>> } else { >>>>>> tokenPtr->type = TCL_TOKEN_COMMAND; >>>>>> } >>>>>> >>>>>> ... >>>>>> >>>>>> In the function TclCompileTokens (file tclCompile.c), I add : >>>>>> >>>>>> case TCL_TOKEN_SUB_EXPR : >>>>>> envPtr->line += adjust; >>>>>> TclCompileExpr(interp, tokenPtr->start+1, tokenPtr->size-2, envPtr, 0); >>>>>> envPtr->line -= adjust; >>>>>> numObjsToConcat++; >>>>>> >>>>>> break; >>>>>> >>>>>> --------------------- >>>>>> >>>>>> Then, I can write : >>>>>> >>>>>> % set x [(1+1)] >>>>>> >>>>>> 2 >>>>>> >>>>>> % set y [($x + [(1 + 1)] )] >>>>>> >>>>>> 4 >>>>>> >>>>>> % set z [($y + [($x * [(1+1)] )] )] >>>>>> >>>>>> 8 >>>>>> >>>>>> ----------------------------- >>>>>> >>>>>> Surely there is corner cases that this prototype doesn't resolve. More investigations are needed and it should be extensively tested, but this prove that the [(...)] expression shorthand is possible at little cost. Maybe even the TCL_TOKEN_SUB_EXPR Token could be used instead of creating a synthetic string. I may investigate this las option later... >>>>>> >>>>>> Florent >>>>>> >>>> _______________________________________________ Tcl-Core mailing list Tcl...@li... https://lists.sourceforge.net/lists/listinfo/tcl-core >>> >>> -- >>> <center> >>> <hr/> >>> <b>Florent MERLET</b><br/> >>> <i>4 rue Johann Strauss<br/> >>> Logement 7<br/> >>> 86180 BUXEROLLES</i><br/> >>> <hr/> >>> <b>Mél.</b> : <i>flo...@gm...</i><br/> >>> <b>Tél.</b> : <i>06 70 00 63 48</i> >>> </center> >>> >>> >>> _______________________________________________ >>> Tcl-Core mailing list >>> Tcl...@li... >>> https://lists.sourceforge.net/lists/listinfo/tcl-core >>> >>> >>> *Attachments:* >>> • summary of changes.xlsx >> > > -- > <center> > <hr/> > <b>Florent MERLET</b><br/> > <i>4 rue Johann Strauss<br/> > Logement 7<br/> > 86180 BUXEROLLES</i><br/> > <hr/> > <b>Mél.</b> : <i>flo...@gm...</i><br/> > <b>Tél.</b> : <i>06 70 00 63 48</i> > </center> |
|
From: Florent M. <flo...@gm...> - 2026-04-23 16:03:52
|
Hi Mason, I also prefer to give name to the things. It is always more readable than obscure syntax chars. That's why, to take your example, I will write it like this : [( ycoord = $y + 5; zcoord = $z * 10; )] lappend X $ycoord $zcoord Despite the unnecessary spaces I added for clarity, what I wrote is only 68 chars, what is 23 chars less than you example (16 % less). And it is not less readable. Don't forget : it includes TIP 282, List capabilities, and "Muting inline expression" (thanks to the trailing semi-colon), so you can reduce the number of '[( ... )]'. You can group many calculation in between. Try it there : https://github.com/florentis/tcl90-exprSH/tree/core-9-0-branch/install_SH Regards Florent Le 23/04/2026 à 17:09, Mason McParlane a écrit : > Terseness does not improve readability. Programming is 80% reading 20% > writing. Just throwing those numbers there's no science behind it but > I'm sure everyone has felt the impact of reading other people's code. > It is difficult to get into the minds of others. I say that because, > regardless of how easy or difficult a change might be to implement, or > how useful it might be for some, to put something in the core that > encourages people to write non-idiomatic code can be problematic. By > that I mean, variables without sigils; cryptic commands like "(" and > ")" which belong in the realm of lisp. > > Here is some facts why this doesn't work well, based on the Gestalt > theory of grouping > (https://en.wikipedia.org/wiki/Principles_of_grouping). The following > is very difficult to read because the "[(" and ")]" has more visual > weight than the expression itself. Having the "expr" word helps soften > the visual weight of brackets in close proximity. > > lappend X [($y+5)] [($z*10)]; > > While it seems easier to write, and perhaps it is, it is much more > difficult to read than: > > set ycoord [expr {$y + 5}] > set zcoord [expr {$z * 10}] > lappend X $ycoord $zcoord > > I realize that the intent is probably for more complex expressions > than those examples, but this hopefully shows that there is a serious > downside to having these in the core when it comes to readability. > > > Mason > > > > On Thu, Apr 23, 2026, at 10:40 AM, Florent Merlet wrote: >> Hi Martin, Peter, Community, >> >> Code impact is only 259 lines of code. >> 2 enums , 4 C-array updated, 11 functions modified, in 4 files. >> >> It is not much. It's not immense as you assert. >> It's very little for the effect ! >> >> Here is a summary of the changes : >> >> kind / part Subst Script TIP282 List Total (kind) >> new lines 75 55 51 24 205 >> line changed 1 0 2 2 5 >> line space / comment 15 13 13 8 49 >> Total (part) 91 68 66 34 259 >> >> >> NB : Each "part" is one part of the Proposal : >> * Subst is for '[( ... )]' shorthand expression substitution >> * Script is for script substitution (ex : eval (1+1) ; proc P {} {( >> ... )}; if {...} then (0) else "($res)" ; ...etc) >> * TIP 282 is for SEPARATOR and ASSIGNEMENT : 'expr {a = 1; b = 2}' >> * List is for list handling : 'expr {(1, 2, 3, 4)}' >> >> You'll find an Excel File in attachement for more details. >> >> [ Notice that I removed the most problematic part (substitution of >> array index) : >> It appears that an index can be parsed in the middle of execution. >> As to compute an index with expr, I needed to compile bytecodes, it >> was not doable.] >> >> I respect your opinion, but, I think you didn't try the implementation. >> There may be some misunderstanding. >> >> Myself, I could load a big package tcllib::math, nothing was >> complaining. >> Of course, lot of tests have to be made. >> >> I recieved opinions, more encouraging than yours : >> >> AMB wrote in the Wiki yesterday (ref >> https://wiki.tcl-lang.org/page/A+Better+way+to+do+calculations >> <https://wiki.tcl-lang.org/page/A+Better+way+to+do+calculations>) >> -------------------------------------------------- >> *AMB <https://wiki.tcl-lang.org/page/AMB> - 2026-04-22 19:47:30* >> >> I downloaded your prototype, FM <https://wiki.tcl-lang.org/page/FM>, >> and it's great!! >> >> ----------------------------------------------------------------- >> >> Ok, he would like to allow spaces before and after the parentheses. >> We could use Tcl_ParseWhiteSpace for this, but It must be discussed. >> I prefer to have something that look like a two-char symbol `[(` `{(` >> `"(`. But, in console context, why not ? >> >> Whatever. Now there is a prototype. >> Before any new change, it's better everybody can play with this >> prototype and comment it. >> My time is counted also, that's why I count on the community feedback. >> >> I 'm proposing you to try the prototype first (for windows, >> statically compiled with gcc, under mingwin). >> You'll find it at : >> https://github.com/florentis/tcl90-exprSH/tree/core-9-0-branch/install_SH >> <https://github.com/florentis/tcl90-exprSH/tree/core-9-0-branch/install_SH> >> >> The actual version of the TIP text, which must be improved, can be >> found at : >> https://github.com/florentis/tcl90-exprSH/blob/core-9-0-branch/TIP_Expr_Shorthand.md >> <https://github.com/florentis/tcl90-exprSH/blob/core-9-0-branch/TIP_Expr_Shorthand.md> >> >> Then you can give an opinion founded on facts, not on what it may be, >> at the view of a long mailing list discussion. >> >> Regards, Tchüss, >> >> Florent >> >> >> Le 22/04/2026 à 23:27, Martin Lemburg a écrit : >>> Reading all the content provided by you, Florent, my gut feeling >>> about not wanting those changes gets louder, stronger. >>> The changes let us win some simplicity in using mathmatics everywhere. >>> The costs are imense, since basic things changes like you just >>> described. >>> Additionally, the costs of changes in several parts of the tcl >>> sources and probably introduced bugs (no one develops in a complex >>> environment without introducing bugs) encourage my gut to shake his >>> head, mourning "no, no, no". >>> To introduce a new command with a "new" little language only for >>> mathmathics is one (quite discussable) thing - not changing parts of >>> tcl parser. >>> The changes you propose are much wider/deeper in their consequences >>> and the longer I think of them the more I think, that they are too >>> risky and that they go too far. >>> Best regards >>> Martin Lemburg >>> Berlin / Germany >>> >>> mar...@gm... <mailto:mar...@gm...> >>> *Gesendet: *Mittwoch, 22. April 2026 um 22:19 >>> *Von: *"Florent Merlet" <flo...@gm...> >>> <mailto:flo...@gm...> >>> *An: *"da Silva, Peter J" <pet...@fl...> >>> <mailto:pet...@fl...>, >>> "tcl...@li..." >>> <mailto:tcl...@li...> >>> <tcl...@li...> <mailto:tcl...@li...> >>> *Betreff: *Re: [TCLCORE] Variation on the Expr Shorthand >>> Le 22/04/2026 à 16:50, da Silva, Peter J a écrit : >>> >>> OK: >>> % proc ( {args} { puts "( $args" } >>> % ( hello ) >>> ( hello ) >>> This is legal existing syntax. >>> >>> Hi Peter, >>> >>> It's still legal, but the meaning is different : it makes '(' a >>> meaningfull symbol in some context. >>> >>> If you want a '(' proc, it would then be like it is now with '[' >>> proc, '{' proc or {"} proc : >>> You would have to protect it with backslah when you call it. >>> Like it is now : >>> >>> % \( hello ) >>> ( hello ) >>> % set a [\( hello )] >>> ( hello ) >>> % proc A {} {\( hello )} >>> % A >>> ( hello ) >>> >>> There is clearly a choice to be made. >>> >>> Is it acceptable to be forced to add an extra backslah to call the >>> "(" proc, >>> just to gain at least 4 chars for each expression used in a script ? >>> >>> My opinion is "yes", it is very acceptable, because I never use any >>> "(" proc, and because I'm fade up writing things like : >>> >>> set a [expr {...}] >>> set b [expr {...}] >>> >>> Without hesitation, I prefer to write : >>> >>> [(a = ...; b = ...;)] >>> >>> Even in including some non essential whitespace for clarity, the >>> last is only 21 chars, whereas the first is 36 chars. >>> So, I can still call the "(" proc 15 times, whithout any loss. >>> >>> My deep opinion is even it would be unacceptable to not accept it. >>> >>> But I would understand it exists other opinions. >>> >>> Regards >>> >>> *From: *Florent Merlet <flo...@gm...> >>> <mailto:flo...@gm...> >>> *Date: *Wednesday, April 22, 2026 at 06:41 >>> *To: *da Silva, Peter J (USA) <pet...@fl...> >>> <mailto:pet...@fl...>; >>> tcl...@li... >>> <mailto:tcl...@li...> >>> <tcl...@li...> >>> <mailto:tcl...@li...> >>> *Subject: *Re: [TCLCORE] Variation on the Expr Shorthand >>> CAUTION - EXTERNAL EMAIL: >>> This message originated from outside of your organization. Do >>> not click links or open attachments unless you recognize the >>> sender and know the content is safe. >>> Le 29/10/2025 à 15:56, da Silva, Peter J a écrit : >>> >>> That has the same problem of breaking existing syntax. >>> % proc ( {args} { puts $args } >>> % ( hello >>> hello >>> >>> >>> Hi Peter, >>> >>> No, It doesn't : check -> >>> https://github.com/florentis/tcl90-exprSH/tree/core-9-0-branch/install_SH/bin >>> <https://urldefense.us/v2/url?u=https-3A__github.com_florentis_tcl90-2DexprSH_tree_core-2D9-2D0-2Dbranch_install-5FSH_bin&d=DwMDaQ&c=MASr1KIcYm9UGIT-jfIzwQg1YBeAkaJoBtxV_4o83uQ&r=BRyGRggIJd8TmKOhvEmGElFuDuCl3O5mT8opva3f-Uc&m=w2tfEZJ11k3zrwJuBQ24gT2PBdBoy0rWTxoFVW7mf-Wmbu-TPHMsSUmUoCydsS8B&s=TQbNb_jQH5uxu4bjbvHKXOCChssskqh-ohkPZULZRnI&e=> >>> >>> >>> I) In *console wish context* : >>> a) No closed paren -> _proc_ >>> (bin) 4 % ( hello >>> hello >>> -> ie : The last argument must finish with a ')' >>> >>> b) First char = open paren, last char = closed paren -> >>> _expression_ >>> 5 % ( hello ) >>> invalid bareword "hello" >>> in expression "( hello ) >>> "; >>> should be "$hello" or "{hello}" or "hello(...)" or ... >>> >>> -> If ever, add a space before the open parenthese or after the >>> close parenthese. >>> >>> c) First char = open paren, last char = space -> _proc_ >>> 6 % ( hello ) ; >>> hello >>> >>> d) First char = space, last char = close paren -> _proc_ >>> 7 % ( hello ) >>> hello ) >>> >>> II) In *script context*, it's also true : >>> a) No closed paren >>> (bin) 8 % proc A {} {( hello} >>> (bin) 9 % A >>> hello >>> b) First char = open paren, last char = closed paren -> >>> _expression_ >>> (bin) 10 % proc B {} {( hello )} >>> (bin) 11 % B >>> invalid bareword "hello" >>> in expression "( hello )"; >>> should be "$hello" or "{hello}" or "hello(...)" or ... >>> >>> c) First char = open paren, last char = space -> _proc_ >>> (bin) 12 % proc C {} {( hello ) } >>> (bin) 13 % C >>> hello ) >>> >>> d) First char = space, last char = closed paren -> _proc_ >>> (bin) 14 % proc D {} { ( hello)} >>> (bin) 15 % D >>> hello) >>> >>> III) In *substitution context*, I have to implement it when >>> coming back from expr with parsing error, to get the same effect. >>> I think it's doable. >>> >>> a) No closed paren : -> expression/ (to be corrected, should be >>> proc)/ >>> (bin) 16 % set A [( hello ] >>> invalid bareword "hello" >>> in expression "( hello ] >>> "; >>> should be "$hello" or "{hello}" or "hello(...)" or ... >>> >>> b) first char = open paren, last char = close paren -> expression. >>> (bin) 17 % set B [( hello )] >>> invalid bareword "hello" >>> in expression "( hello )] >>> "; >>> should be "$hello" or "{hello}" or "hello(...)" or ... >>> >>> c) First char = space, , last char = close paren -> proc >>> (bin) 18 % set C [ ( hello )] >>> hello ) >>> >>> d) first char = open paren, last char = space -> expression /(to >>> be corrected, should be proc)/ >>> (bin) 16 % set D [( hello ) ] >>> invalid bareword "hello" >>> in expression "( hello ) ] >>> "; >>> should be "$hello" or "{hello}" or "hello(...)" or ... >>> >>> Regards >>> >>> *From: *Florent Merlet <flo...@gm...> >>> <mailto:flo...@gm...> >>> *Date: *Wednesday, October 29, 2025 at 09:45 >>> *To: *tcl...@li... >>> <mailto:tcl...@li...> >>> <tcl...@li...> >>> <mailto:tcl...@li...> >>> *Subject: *[TCLCORE] Variation on the Expr Shorthand >>> CAUTION - EXTERNAL EMAIL: >>> This message originated from outside of your organization. >>> Do not click links or open attachments unless you recognize >>> the sender and know the content is safe. >>> >>> Hi dear Tcl community, >>> >>> An Expr shorthand syntax has been a long time demand between us. >>> >>> Those discussions always focus on the syntax aspect of the >>> subject : >>> >>> * Like in bash $(...) or $((...)) >>> * Through an alias [= ...] >>> * A new command (vexpr or let) >>> * A word prefix {=} >>> * ... >>> >>> A lot of TIPs exists on that matter. Numerous discussions >>> occurs, which never ended to get a consensus. >>> >>> That's because the look of this shorthand is a matter of >>> taste. Everybody has his own taste. Some people like fish >>> when it's cooked in water, some people like it when it's >>> fried. Some people even don't like fish at all ! Every taste >>> is in the nature. >>> >>> Everybody can agree that Tcl is a big and complex machinery, >>> that must be handled with care. So maybe the problem must be >>> taken the other way round : >>> >>> * Shall we deduce the Tcl C source code machinery from a >>> new syntax, we had previously decided (the one doesn't >>> make consensus) >>> * Or shall we deduce the new syntax from the Tcl C source >>> code machinery, as it exists ? >>> >>> My opinion is that it's better to deduce the syntax from the >>> Tcl C source code, rather than to deduce the Tcl source C >>> code from the syntax . >>> >>> TIP 672 is hacking the variable substitution. To do this, it >>> has to make a very basic parsing of the expression to >>> estimate its length. It has to transmute a TCL_VARIABLE >>> Token into a TCL_COMMAND token. It then use a call to >>> Tcl_ParseCommand on a synthetic string to check errors. >>> >>> This very basic parsing will make it buggy. For instance, a >>> shorthand expression can't be nested in another one. A quote >>> inside braces would create an error. To make this parsing >>> strong, we would have to reinvent all the expression parsing >>> from scratch. >>> >>> But shall we create a new parsing expression routine for >>> this shorthand ? No, there exist already an expression >>> parsing machinery, that can handle words between Quotes or >>> Braces and can handle Nested Commands, exactly how the Expr >>> command do. >>> >>> « Deduce the shorthand syntax from the Tcl C source Code » >>> imply to find a syntax which allows us to use the existing >>> machinery. >>> >>> That's what I'm trying now : >>> >>> As Expr is a command in Tcl, it seems logical to me to >>> implement the shorthand syntax in the Command branch "[" of >>> parseToken procedure. That's what I choosed. >>> >>> The second step is to parse the expression, so to go through >>> Tcl_ParseExpr routine, then to the ParseExpr routine. The >>> difficulty here is to get the end of the substitution script >>> in the ParseExpr routine. If I don't want to disturb >>> parseExpr too much, it's better to choose, as character >>> which ends the expression script, a character that >>> is significant for this parser, so the main task of >>> detecting it is already done, but can be adapted gently. >>> >>> Maybe I could have used any of those operators : '+', '=', >>> '-', '*', '(', ')', '|',...etc. But I choosed to use ')' : >>> infix language needs parenthesis. >>> >>> That is how I defined the end of the expression substitution >>> script to be ")]". By symetry, I defined the beginning of >>> the substitution script to be "[(". >>> >>> Here is the genesis of my proposal of "[( ...)]" as a >>> shorthand. >>> >>> To make it work, I had to used the same clever hacking than >>> Eric Taylor : create a synthethic string and parse it as a >>> command. >>> >>> At the end, the [(...)] is working as expected (so far I've >>> tested). Here are the main changes I have done to accomplish >>> it : >>> >>> In file Tcl_Parse.c : in function parseTokens, I add a new >>> branch in the test >>> >>> ---------------------------------------- >>> >>> ... } else if (src[0] == '[' && src[1] == '(') { >>> /////////////////////////////////////////////////////////////////////// >>> >>> /* Expression substition context */ >>> // to do : noSubstExpr >>> Tcl_Parse *exprParsePtr; >>> exprParsePtr =(Tcl_Parse >>> *)TclStackAlloc(parsePtr->interp, sizeof(Tcl_Parse)); >>> >>> src++; // src == '[' >>> numBytes --; >>> // Use it only to know the length of the expression, >>> and store it into exprParsePtr->commandSize >>> Tcl_ParseExpr(parsePtr->interp, src, numBytes, >>> exprParsePtr); >>> >>> src++; // src == '(' >>> numBytes --; >>> >>> // Here is the famous hack of Eric Taylor >>> Tcl_Size syntheticLen = exprParsePtr->commandSize + >>> 9; // "[expr {" + expr + "}]" >>> >>> char *synthetic = (char *)Tcl_Alloc(syntheticLen + 1); >>> >>> memcpy(synthetic, "[expr {", 7); >>> memcpy(synthetic + 7, src, exprParsePtr->commandSize); >>> >>> memcpy(synthetic + 7 + exprParsePtr->commandSize, >>> "}]", 3); >>> synthetic[syntheticLen] = '\0'; >>> // Maybe a Tcl_Obj could be of use for memory >>> management ? >>> >>> Tcl_Obj *exprObjCommand = >>> Tcl_NewStringObj(synthetic,syntheticLen); >>> >>> src+=exprParsePtr->commandSize+2; >>> numBytes-=exprParsePtr->commandSize+2; >>> >>> TclStackFree(parsePtr->interp, exprParsePtr); >>> >>> tokenPtr->type = TCL_TOKEN_COMMAND; >>> tokenPtr->start = >>> Tcl_GetStringFromObj(exprObjCommand, NULL); >>> tokenPtr->size = syntheticLen; >>> parsePtr->numTokens++; >>> >>> continue; >>> >>> } else if (*src == '[') {... >>> >>> --------------------------------------- >>> >>> To detect the end and transfer the size of the parsed >>> expression I had to modify : >>> >>> 1° the Tcl_ParseExpr function : >>> >>> ... if (code == TCL_OK) { >>> if(start[-1] == '[' && start[0] == '(' ) { >>> // Expression Substitution Context : just transfer >>> the size information to the caller >>> parsePtr->commandSize =exprParsePtr->commandSize; >>> } else { >>> TclParseInit(interp, start, numBytes, parsePtr); >>> ConvertTreeToTokens(start, numBytes, >>> opTree, exprParsePtr->tokenPtr, parsePtr); >>> } ... >>> >>> 2° the ParseExpr fonction >>> >>> int nb_paren=0; >>> int substExpressionContext=0; >>> >>> if(start[-1] == '[' && start[0] == '(' ) { >>> substExpressionContext=1; >>> >>> // Expression substitution >>> start++; //skip the open parenthesis '(' : it's part of >>> the expression substitution syntax >>> numBytes--; >>> } >>> >>> ... >>> >>> case UNARY: >>> >>> ////////////////////////////////// >>> >>> if (substExpressionContext == 1) { >>> >>> // Beyond binary operators, there is Open paren, >>> count it >>> >>> if (start[0]== '(') { >>> >>> // Count the open parenthesis in this context >>> >>> nb_paren++; >>> } >>> } >>> >>> case BINARY: { >>> ... >>> if (substExpressionContext == 1) { >>> >>> // Beyond binary operators, there is closed >>> Paren, count it. >>> >>> if (start[0] == ')') { >>> nb_paren--; >>> if (nb_paren == -1 && start[1] ==']') { >>> //// End of expression >>> parsePtr->commandSize = originalLength - >>> numBytes - 1; >>> numBytes=0; >>> continue; // and exit the loop, since >>> numbytes == 0 ;) >>> } >>> } >>> } >>> >>> ---------------------------------------- >>> >>> I add also make it nestable, ie : set x [(1 + [(2+3)] )] >>> >>> in the function Parse_Expr : >>> >>> case SCRIPT : { >>> >>> ... >>> >>> if (start[1] == '(') { >>> >>> // an open braket followed by an open paren is >>> denoting the expression shorthand >>> >>> tokenPtr->type = TCL_TOKEN_SUB_EXPR; >>> } else { >>> tokenPtr->type = TCL_TOKEN_COMMAND; >>> } >>> >>> ... >>> >>> In the function TclCompileTokens (file tclCompile.c), I add : >>> >>> case TCL_TOKEN_SUB_EXPR : >>> envPtr->line += adjust; >>> TclCompileExpr(interp, tokenPtr->start+1, >>> tokenPtr->size-2, envPtr, 0); >>> envPtr->line -= adjust; >>> numObjsToConcat++; >>> >>> break; >>> >>> --------------------- >>> >>> Then, I can write : >>> >>> % set x [(1+1)] >>> >>> 2 >>> >>> % set y [($x + [(1 + 1)] )] >>> >>> 4 >>> >>> % set z [($y + [($x * [(1+1)] )] )] >>> >>> 8 >>> >>> ----------------------------- >>> >>> Surely there is corner cases that this prototype doesn't >>> resolve. More investigations are needed and it should be >>> extensively tested, but this prove that the [(...)] >>> expression shorthand is possible at little cost. Maybe even >>> the TCL_TOKEN_SUB_EXPR Token could be used instead of >>> creating a synthetic string. I may investigate this las >>> option later... >>> >>> Florent >>> >>> _______________________________________________ Tcl-Core mailing >>> list Tcl...@li... >>> <mailto:Tcl...@li...> >>> https://lists.sourceforge.net/lists/listinfo/tcl-core >>> <https://lists.sourceforge.net/lists/listinfo/tcl-core> >> >> -- >> <center> >> <hr/> >> <b>Florent MERLET</b><br/> >> <i>4 rue Johann Strauss<br/> >> Logement 7<br/> >> 86180 BUXEROLLES</i><br/> >> <hr/> >> <b>Mél.</b> : <i>flo...@gm... <mailto:flo...@gm...></i><br/> >> <b>Tél.</b> : <i>06 70 00 63 48</i> >> </center> >> >> >> _______________________________________________ >> Tcl-Core mailing list >> Tcl...@li... >> https://lists.sourceforge.net/lists/listinfo/tcl-core >> >> >> *Attachments:* >> >> * summary of changes.xlsx >> > -- <center> <hr/> <b>Florent MERLET</b><br/> <i>4 rue Johann Strauss<br/> Logement 7<br/> 86180 BUXEROLLES</i><br/> <hr/> <b>Mél.</b> : <i>flo...@gm...</i><br/> <b>Tél.</b> : <i>06 70 00 63 48</i> </center> |
|
From: EricT <tw...@gm...> - 2026-04-23 15:33:45
|
Hi Yorik,
Thanks for those 2 procedures.
The first one compared to code using braced expr has about a 4.5x
performance decrease.
However, the second example, was quite more, there I found a 40x decrease.
Do you find the same results?
Eric
On Thu, Apr 23, 2026 at 7:30 AM Zaumseil René via Tcl-Core <
tcl...@li...> wrote:
> Hello Yorick
>
> Very cool. It reminds me of my own "let" proposal.
> Imho these 2 functions should go at least in the ::tcl namespace.
> The big problem is to find proper names.
>
> For the first "= {..} {..}" I would propose "tcl::lexpr ..
> For the second "= x .. y.." I would propose "tcl::let .."
>
> This is like TIP 760.
>
> Thank you
> rene
>
>
> -----Ursprüngliche Nachricht-----
> Von: Poor Yorick <org...@po...>
> Gesendet: Donnerstag, 23. April 2026 11:36
> An: tcl...@li...
> Betreff: [Ext] Re: [TCLCORE] TIP 676 results - doesn't pass
>
> On 2026-04-23 11:28, EricT wrote:
> > Hi Poor,
> >
> > Can you elaborate on your = helper here?
> >
> > Is this something that takes each argument and passes it on to expr,
> > and then returns a list of results? If so, can you pass it to expr
> > braced so it compiles efficiently?
> >
> > Regards,
> >
> > Eric
>
> Here is it is:
>
> proc = args {
> lmap item $args[set args {}] {uplevel 1 [list ::expr
> $item]}
> }
>
> Example:
>
> .canvas addtag enclosed {*}[= {$x-20} {$x+20} {$y-20} {$y+20}]
>
>
> If that isn't efficient enough, then making the necessary to changes to
> Tcl to make it more efficient would be a good direction.
>
> But I would call that something like lexpr so that = could be used to make
> expr more convenient:
>
> proc = args {
> uplevel 1 [join [lmap {varname expr} $args[set args {}] {
> lindex "::set [list $varname] \[::expr [list
> $expr]]"
> }] \n]
> }
>
> Example:
>
> = x {3 * 3.14} y {$x * 2}
>
> Those two procedures make doing math in Tcl pretty reasonable, without any
> language modification.
>
> --
> Yorick
>
>
> _______________________________________________
> Tcl-Core mailing list
> Tcl...@li...
> https://lists.sourceforge.net/lists/listinfo/tcl-core
>
>
> _______________________________________________
> Tcl-Core mailing list
> Tcl...@li...
> https://lists.sourceforge.net/lists/listinfo/tcl-core
>
|
|
From: Mason M. <ma...@ba...> - 2026-04-23 15:10:24
|
Terseness does not improve readability. Programming is 80% reading 20% writing. Just throwing those numbers there's no science behind it but I'm sure everyone has felt the impact of reading other people's code. It is difficult to get into the minds of others. I say that because, regardless of how easy or difficult a change might be to implement, or how useful it might be for some, to put something in the core that encourages people to write non-idiomatic code can be problematic. By that I mean, variables without sigils; cryptic commands like "(" and ")" which belong in the realm of lisp.
Here is some facts why this doesn't work well, based on the Gestalt theory of grouping (https://en.wikipedia.org/wiki/Principles_of_grouping). The following is very difficult to read because the "[(" and ")]" has more visual weight than the expression itself. Having the "expr" word helps soften the visual weight of brackets in close proximity.
lappend X [($y+5)] [($z*10)];
While it seems easier to write, and perhaps it is, it is much more difficult to read than:
set ycoord [expr {$y + 5}]
set zcoord [expr {$z * 10}]
lappend X $ycoord $zcoord
I realize that the intent is probably for more complex expressions than those examples, but this hopefully shows that there is a serious downside to having these in the core when it comes to readability.
Mason
On Thu, Apr 23, 2026, at 10:40 AM, Florent Merlet wrote:
> Hi Martin, Peter, Community,
>
> Code impact is only 259 lines of code.
> 2 enums , 4 C-array updated, 11 functions modified, in 4 files.
>
> It is not much. It's not immense as you assert.
> It's very little for the effect !
>
> Here is a summary of the changes :
>
> kind / part Subst Script TIP282 List Total (kind)
> new lines 75 55 51 24 205
> line changed 1 0 2 2 5
> line space / comment 15 13 13 8 49
> Total (part) 91 68 66 34 259
>
> NB : Each "part" is one part of the Proposal :
> * Subst is for '[( ... )]' shorthand expression substitution
> * Script is for script substitution (ex : eval (1+1) ; proc P {} {( ... )}; if {...} then (0) else "($res)" ; ...etc)
> * TIP 282 is for SEPARATOR and ASSIGNEMENT : 'expr {a = 1; b = 2}'
> * List is for list handling : 'expr {(1, 2, 3, 4)}'
>
> You'll find an Excel File in attachement for more details.
>
> [ Notice that I removed the most problematic part (substitution of array index) :
> It appears that an index can be parsed in the middle of execution. As to compute an index with expr, I needed to compile bytecodes, it was not doable.]
>
> I respect your opinion, but, I think you didn't try the implementation.
> There may be some misunderstanding.
>
> Myself, I could load a big package tcllib::math, nothing was complaining.
> Of course, lot of tests have to be made.
>
> I recieved opinions, more encouraging than yours :
>
> AMB wrote in the Wiki yesterday (ref https://wiki.tcl-lang.org/page/A+Better+way+to+do+calculations)
> --------------------------------------------------
> *AMB <https://wiki.tcl-lang.org/page/AMB> - 2026-04-22 19:47:30*
> I downloaded your prototype, FM <https://wiki.tcl-lang.org/page/FM>, and it's great!!
>
> -----------------------------------------------------------------
>
> Ok, he would like to allow spaces before and after the parentheses. We could use Tcl_ParseWhiteSpace for this, but It must be discussed.
> I prefer to have something that look like a two-char symbol `[(` `{(` `"(`. But, in console context, why not ?
>
> Whatever. Now there is a prototype.
> Before any new change, it's better everybody can play with this prototype and comment it.
> My time is counted also, that's why I count on the community feedback.
>
> I 'm proposing you to try the prototype first (for windows, statically compiled with gcc, under mingwin).
> You'll find it at : https://github.com/florentis/tcl90-exprSH/tree/core-9-0-branch/install_SH
>
> The actual version of the TIP text, which must be improved, can be found at :
> https://github.com/florentis/tcl90-exprSH/blob/core-9-0-branch/TIP_Expr_Shorthand.md
>
> Then you can give an opinion founded on facts, not on what it may be, at the view of a long mailing list discussion.
>
> Regards, Tchüss,
>
> Florent
>
>
> Le 22/04/2026 à 23:27, Martin Lemburg a écrit :
>> Reading all the content provided by you, Florent, my gut feeling about not wanting those changes gets louder, stronger.
>>
>> The changes let us win some simplicity in using mathmatics everywhere.
>> The costs are imense, since basic things changes like you just described.
>>
>> Additionally, the costs of changes in several parts of the tcl sources and probably introduced bugs (no one develops in a complex environment without introducing bugs) encourage my gut to shake his head, mourning "no, no, no".
>>
>> To introduce a new command with a "new" little language only for mathmathics is one (quite discussable) thing - not changing parts of tcl parser.
>> The changes you propose are much wider/deeper in their consequences and the longer I think of them the more I think, that they are too risky and that they go too far.
>>
>> Best regards
>>
>> Martin Lemburg
>> Berlin / Germany
>>
>> mar...@gm...
>> *Gesendet: *Mittwoch, 22. April 2026 um 22:19
>> *Von: *"Florent Merlet" <flo...@gm...>
>> *An: *"da Silva, Peter J" <pet...@fl...>, "tcl...@li..." <tcl...@li...>
>> *Betreff: *Re: [TCLCORE] Variation on the Expr Shorthand
>> Le 22/04/2026 à 16:50, da Silva, Peter J a écrit :
>>> OK:
>>>
>>> % proc ( {args} { puts "( $args" }
>>> % ( hello )
>>> ( hello )
>>>
>>> This is legal existing syntax.
>>>
>> Hi Peter,
>>
>> It's still legal, but the meaning is different : it makes '(' a meaningfull symbol in some context.
>>
>> If you want a '(' proc, it would then be like it is now with '[' proc, '{' proc or {"} proc :
>> You would have to protect it with backslah when you call it.
>> Like it is now :
>>
>> % \( hello )
>> ( hello )
>> % set a [\( hello )]
>> ( hello )
>> % proc A {} {\( hello )}
>> % A
>> ( hello )
>>
>> There is clearly a choice to be made.
>>
>> Is it acceptable to be forced to add an extra backslah to call the "(" proc,
>> just to gain at least 4 chars for each expression used in a script ?
>>
>> My opinion is "yes", it is very acceptable, because I never use any "(" proc, and because I'm fade up writing things like :
>>
>> set a [expr {...}]
>> set b [expr {...}]
>>
>> Without hesitation, I prefer to write :
>>
>> [(a = ...; b = ...;)]
>>
>> Even in including some non essential whitespace for clarity, the last is only 21 chars, whereas the first is 36 chars.
>> So, I can still call the "(" proc 15 times, whithout any loss.
>>
>> My deep opinion is even it would be unacceptable to not accept it.
>>
>> But I would understand it exists other opinions.
>>
>> Regards
>>>
>>>
>>> *From: *Florent Merlet <flo...@gm...>
>>> *Date: *Wednesday, April 22, 2026 at 06:41
>>> *To: *da Silva, Peter J (USA) <pet...@fl...>; tcl...@li... <tcl...@li...>
>>> *Subject: *Re: [TCLCORE] Variation on the Expr Shorthand
>>> CAUTION - EXTERNAL EMAIL:
>>> This message originated from outside of your organization. Do not click links or open attachments unless you recognize the sender and know the content is safe.
>>>
>>> Le 29/10/2025 à 15:56, da Silva, Peter J a écrit :
>>>> That has the same problem of breaking existing syntax.
>>>>
>>>> % proc ( {args} { puts $args }
>>>> % ( hello
>>>> hello
>>>
>>> Hi Peter,
>>>
>>> No, It doesn't : check -> https://github.com/florentis/tcl90-exprSH/tree/core-9-0-branch/install_SH/bin <https://urldefense.us/v2/url?u=https-3A__github.com_florentis_tcl90-2DexprSH_tree_core-2D9-2D0-2Dbranch_install-5FSH_bin&d=DwMDaQ&c=MASr1KIcYm9UGIT-jfIzwQg1YBeAkaJoBtxV_4o83uQ&r=BRyGRggIJd8TmKOhvEmGElFuDuCl3O5mT8opva3f-Uc&m=w2tfEZJ11k3zrwJuBQ24gT2PBdBoy0rWTxoFVW7mf-Wmbu-TPHMsSUmUoCydsS8B&s=TQbNb_jQH5uxu4bjbvHKXOCChssskqh-ohkPZULZRnI&e=>
>>>
>>> I) In *console wish context* :
>>> a) No closed paren -> _proc_
>>> (bin) 4 % ( hello
>>> hello
>>> -> ie : The last argument must finish with a ')'
>>>
>>> b) First char = open paren, last char = closed paren -> _expression_
>>> 5 % ( hello )
>>> invalid bareword "hello"
>>> in expression "( hello )
>>> ";
>>> should be "$hello" or "{hello}" or "hello(...)" or ...
>>>
>>> -> If ever, add a space before the open parenthese or after the close parenthese.
>>>
>>> c) First char = open paren, last char = space -> _proc_
>>> 6 % ( hello ) ;
>>> hello
>>>
>>> d) First char = space, last char = close paren -> _proc_
>>> 7 % ( hello )
>>> hello )
>>>
>>> II) In *script context*, it's also true :
>>> a) No closed paren
>>> (bin) 8 % proc A {} {( hello}
>>> (bin) 9 % A
>>> hello
>>> b) First char = open paren, last char = closed paren -> _expression_
>>> (bin) 10 % proc B {} {( hello )}
>>> (bin) 11 % B
>>> invalid bareword "hello"
>>> in expression "( hello )";
>>> should be "$hello" or "{hello}" or "hello(...)" or ...
>>>
>>> c) First char = open paren, last char = space -> _proc_
>>> (bin) 12 % proc C {} {( hello ) }
>>> (bin) 13 % C
>>> hello )
>>>
>>> d) First char = space, last char = closed paren -> _proc_
>>> (bin) 14 % proc D {} { ( hello)}
>>> (bin) 15 % D
>>> hello)
>>>
>>> III) In *substitution context*, I have to implement it when coming back from expr with parsing error, to get the same effect.
>>> I think it's doable.
>>>
>>> a) No closed paren : -> expression* (to be corrected, should be proc)*
>>> (bin) 16 % set A [( hello ]
>>> invalid bareword "hello"
>>> in expression "( hello ]
>>> ";
>>> should be "$hello" or "{hello}" or "hello(...)" or ...
>>>
>>> b) first char = open paren, last char = close paren -> expression.
>>> (bin) 17 % set B [( hello )]
>>> invalid bareword "hello"
>>> in expression "( hello )]
>>> ";
>>> should be "$hello" or "{hello}" or "hello(...)" or ...
>>>
>>> c) First char = space, , last char = close paren -> proc
>>> (bin) 18 % set C [ ( hello )]
>>> hello )
>>>
>>> d) first char = open paren, last char = space -> expression *(to be corrected, should be proc)*
>>> (bin) 16 % set D [( hello ) ]
>>> invalid bareword "hello"
>>> in expression "( hello ) ]
>>> ";
>>> should be "$hello" or "{hello}" or "hello(...)" or ...
>>>
>>> Regards
>>>
>>>>
>>>> *From: *Florent Merlet <flo...@gm...>
>>>> *Date: *Wednesday, October 29, 2025 at 09:45
>>>> *To: *tcl...@li... <tcl...@li...>
>>>> *Subject: *[TCLCORE] Variation on the Expr Shorthand
>>>> CAUTION - EXTERNAL EMAIL:
>>>> This message originated from outside of your organization. Do not click links or open attachments unless you recognize the sender and know the content is safe.
>>>>
>>>> Hi dear Tcl community,
>>>>
>>>> An Expr shorthand syntax has been a long time demand between us.
>>>>
>>>> Those discussions always focus on the syntax aspect of the subject :
>>>>
>>>> • Like in bash $(...) or $((...))
>>>> • Through an alias [= ...]
>>>> • A new command (vexpr or let)
>>>> • A word prefix {=}
>>>> • ...
>>>> A lot of TIPs exists on that matter. Numerous discussions occurs, which never ended to get a consensus.
>>>>
>>>> That's because the look of this shorthand is a matter of taste. Everybody has his own taste. Some people like fish when it's cooked in water, some people like it when it's fried. Some people even don't like fish at all ! Every taste is in the nature.
>>>>
>>>> Everybody can agree that Tcl is a big and complex machinery, that must be handled with care. So maybe the problem must be taken the other way round :
>>>>
>>>> • Shall we deduce the Tcl C source code machinery from a new syntax, we had previously decided (the one doesn't make consensus)
>>>> • Or shall we deduce the new syntax from the Tcl C source code machinery, as it exists ?
>>>> My opinion is that it's better to deduce the syntax from the Tcl C source code, rather than to deduce the Tcl source C code from the syntax .
>>>>
>>>> TIP 672 is hacking the variable substitution. To do this, it has to make a very basic parsing of the expression to estimate its length. It has to transmute a TCL_VARIABLE Token into a TCL_COMMAND token. It then use a call to Tcl_ParseCommand on a synthetic string to check errors.
>>>>
>>>> This very basic parsing will make it buggy. For instance, a shorthand expression can't be nested in another one. A quote inside braces would create an error. To make this parsing strong, we would have to reinvent all the expression parsing from scratch.
>>>>
>>>> But shall we create a new parsing expression routine for this shorthand ? No, there exist already an expression parsing machinery, that can handle words between Quotes or Braces and can handle Nested Commands, exactly how the Expr command do.
>>>>
>>>> « Deduce the shorthand syntax from the Tcl C source Code » imply to find a syntax which allows us to use the existing machinery.
>>>>
>>>> That's what I'm trying now :
>>>>
>>>> As Expr is a command in Tcl, it seems logical to me to implement the shorthand syntax in the Command branch "[" of parseToken procedure. That's what I choosed.
>>>>
>>>> The second step is to parse the expression, so to go through Tcl_ParseExpr routine, then to the ParseExpr routine. The difficulty here is to get the end of the substitution script in the ParseExpr routine. If I don't want to disturb parseExpr too much, it's better to choose, as character which ends the expression script, a character that is significant for this parser, so the main task of detecting it is already done, but can be adapted gently.
>>>>
>>>> Maybe I could have used any of those operators : '+', '=', '-', '*', '(', ')', '|',...etc. But I choosed to use ')' : infix language needs parenthesis.
>>>>
>>>> That is how I defined the end of the expression substitution script to be ")]". By symetry, I defined the beginning of the substitution script to be "[(".
>>>>
>>>> Here is the genesis of my proposal of "[( ...)]" as a shorthand.
>>>>
>>>> To make it work, I had to used the same clever hacking than Eric Taylor : create a synthethic string and parse it as a command.
>>>>
>>>> At the end, the [(...)] is working as expected (so far I've tested). Here are the main changes I have done to accomplish it :
>>>>
>>>> In file Tcl_Parse.c : in function parseTokens, I add a new branch in the test
>>>>
>>>> ----------------------------------------
>>>>
>>>> ... } else if (src[0] == '[' && src[1] == '(') {
>>>> ///////////////////////////////////////////////////////////////////////
>>>> /* Expression substition context */
>>>> // to do : noSubstExpr
>>>> Tcl_Parse *exprParsePtr;
>>>> exprParsePtr =(Tcl_Parse *)TclStackAlloc(parsePtr->interp, sizeof(Tcl_Parse));
>>>>
>>>> src++; // src == '['
>>>> numBytes --;
>>>> // Use it only to know the length of the expression, and store it into exprParsePtr->commandSize
>>>> Tcl_ParseExpr(parsePtr->interp, src, numBytes, exprParsePtr);
>>>>
>>>> src++; // src == '('
>>>> numBytes --;
>>>>
>>>> // Here is the famous hack of Eric Taylor
>>>> Tcl_Size syntheticLen = exprParsePtr->commandSize + 9; // "[expr {" + expr + "}]"
>>>>
>>>> char *synthetic = (char *)Tcl_Alloc(syntheticLen + 1);
>>>>
>>>> memcpy(synthetic, "[expr {", 7);
>>>> memcpy(synthetic + 7, src, exprParsePtr->commandSize);
>>>>
>>>> memcpy(synthetic + 7 + exprParsePtr->commandSize, "}]", 3);
>>>> synthetic[syntheticLen] = '\0';
>>>> // Maybe a Tcl_Obj could be of use for memory management ?
>>>>
>>>> Tcl_Obj *exprObjCommand = Tcl_NewStringObj(synthetic,syntheticLen);
>>>>
>>>> src+=exprParsePtr->commandSize+2;
>>>> numBytes-=exprParsePtr->commandSize+2;
>>>>
>>>> TclStackFree(parsePtr->interp, exprParsePtr);
>>>>
>>>> tokenPtr->type = TCL_TOKEN_COMMAND;
>>>> tokenPtr->start = Tcl_GetStringFromObj(exprObjCommand, NULL);
>>>> tokenPtr->size = syntheticLen;
>>>> parsePtr->numTokens++;
>>>>
>>>> continue;
>>>>
>>>> } else if (*src == '[') {...
>>>>
>>>> ---------------------------------------
>>>>
>>>> To detect the end and transfer the size of the parsed expression I had to modify :
>>>>
>>>> 1° the Tcl_ParseExpr function :
>>>>
>>>> ... if (code == TCL_OK) {
>>>> if(start[-1] == '[' && start[0] == '(' ) {
>>>> // Expression Substitution Context : just transfer the size information to the caller
>>>> parsePtr->commandSize =exprParsePtr->commandSize;
>>>> } else {
>>>> TclParseInit(interp, start, numBytes, parsePtr);
>>>> ConvertTreeToTokens(start, numBytes,
>>>> opTree, exprParsePtr->tokenPtr, parsePtr);
>>>> } ...
>>>>
>>>> 2° the ParseExpr fonction
>>>>
>>>> int nb_paren=0;
>>>> int substExpressionContext=0;
>>>>
>>>> if(start[-1] == '[' && start[0] == '(' ) {
>>>> substExpressionContext=1;
>>>>
>>>> // Expression substitution
>>>> start++; //skip the open parenthesis '(' : it's part of the expression substitution syntax
>>>> numBytes--;
>>>> }
>>>>
>>>> ...
>>>>
>>>> case UNARY:
>>>>
>>>> //////////////////////////////////
>>>>
>>>> if (substExpressionContext == 1) {
>>>>
>>>> // Beyond binary operators, there is Open paren, count it
>>>>
>>>> if (start[0]== '(') {
>>>>
>>>> // Count the open parenthesis in this context
>>>>
>>>> nb_paren++;
>>>> }
>>>> }
>>>>
>>>> case BINARY: {
>>>> ...
>>>> if (substExpressionContext == 1) {
>>>>
>>>> // Beyond binary operators, there is closed Paren, count it.
>>>>
>>>> if (start[0] == ')') {
>>>> nb_paren--;
>>>> if (nb_paren == -1 && start[1] ==']') {
>>>> //// End of expression
>>>> parsePtr->commandSize = originalLength - numBytes - 1;
>>>> numBytes=0;
>>>> continue; // and exit the loop, since numbytes == 0 ;)
>>>> }
>>>> }
>>>> }
>>>>
>>>> ----------------------------------------
>>>>
>>>> I add also make it nestable, ie : set x [(1 + [(2+3)] )]
>>>>
>>>> in the function Parse_Expr :
>>>>
>>>> case SCRIPT : {
>>>>
>>>> ...
>>>>
>>>> if (start[1] == '(') {
>>>>
>>>> // an open braket followed by an open paren is denoting the expression shorthand
>>>>
>>>> tokenPtr->type = TCL_TOKEN_SUB_EXPR;
>>>> } else {
>>>> tokenPtr->type = TCL_TOKEN_COMMAND;
>>>> }
>>>>
>>>> ...
>>>>
>>>> In the function TclCompileTokens (file tclCompile.c), I add :
>>>>
>>>> case TCL_TOKEN_SUB_EXPR :
>>>> envPtr->line += adjust;
>>>> TclCompileExpr(interp, tokenPtr->start+1, tokenPtr->size-2, envPtr, 0);
>>>> envPtr->line -= adjust;
>>>> numObjsToConcat++;
>>>>
>>>> break;
>>>>
>>>> ---------------------
>>>>
>>>> Then, I can write :
>>>>
>>>> % set x [(1+1)]
>>>>
>>>> 2
>>>>
>>>> % set y [($x + [(1 + 1)] )]
>>>>
>>>> 4
>>>>
>>>> % set z [($y + [($x * [(1+1)] )] )]
>>>>
>>>> 8
>>>>
>>>> -----------------------------
>>>>
>>>> Surely there is corner cases that this prototype doesn't resolve. More investigations are needed and it should be extensively tested, but this prove that the [(...)] expression shorthand is possible at little cost. Maybe even the TCL_TOKEN_SUB_EXPR Token could be used instead of creating a synthetic string. I may investigate this las option later...
>>>>
>>>> Florent
>>>>
>> _______________________________________________ Tcl-Core mailing list Tcl...@li... https://lists.sourceforge.net/lists/listinfo/tcl-core
>
> --
> <center>
> <hr/>
> <b>Florent MERLET</b><br/>
> <i>4 rue Johann Strauss<br/>
> Logement 7<br/>
> 86180 BUXEROLLES</i><br/>
> <hr/>
> <b>Mél.</b> : <i>flo...@gm...</i><br/>
> <b>Tél.</b> : <i>06 70 00 63 48</i>
> </center>
>
>
> _______________________________________________
> Tcl-Core mailing list
> Tcl...@li...
> https://lists.sourceforge.net/lists/listinfo/tcl-core
>
>
> *Attachments:*
> • summary of changes.xlsx
|
|
From: da S. P. J <pet...@fl...> - 2026-04-23 15:06:13
|
I don't want a proc named "(", my point is that this *is * a syntax-breaking change. It makes Tcl syntax more complex. There is a concurrent proposal that doesn't require a syntax-breaking change, and is thus preferable.
|
|
From: Zaumseil R. <RZa...@kk...> - 2026-04-23 14:30:31
|
Hello Yorick
Very cool. It reminds me of my own "let" proposal.
Imho these 2 functions should go at least in the ::tcl namespace.
The big problem is to find proper names.
For the first "= {..} {..}" I would propose "tcl::lexpr ..
For the second "= x .. y.." I would propose "tcl::let .."
This is like TIP 760.
Thank you
rene
-----Ursprüngliche Nachricht-----
Von: Poor Yorick <org...@po...>
Gesendet: Donnerstag, 23. April 2026 11:36
An: tcl...@li...
Betreff: [Ext] Re: [TCLCORE] TIP 676 results - doesn't pass
On 2026-04-23 11:28, EricT wrote:
> Hi Poor,
>
> Can you elaborate on your = helper here?
>
> Is this something that takes each argument and passes it on to expr,
> and then returns a list of results? If so, can you pass it to expr
> braced so it compiles efficiently?
>
> Regards,
>
> Eric
Here is it is:
proc = args {
lmap item $args[set args {}] {uplevel 1 [list ::expr $item]}
}
Example:
.canvas addtag enclosed {*}[= {$x-20} {$x+20} {$y-20} {$y+20}]
If that isn't efficient enough, then making the necessary to changes to Tcl to make it more efficient would be a good direction.
But I would call that something like lexpr so that = could be used to make expr more convenient:
proc = args {
uplevel 1 [join [lmap {varname expr} $args[set args {}] {
lindex "::set [list $varname] \[::expr [list $expr]]"
}] \n]
}
Example:
= x {3 * 3.14} y {$x * 2}
Those two procedures make doing math in Tcl pretty reasonable, without any language modification.
--
Yorick
_______________________________________________
Tcl-Core mailing list
Tcl...@li...
https://lists.sourceforge.net/lists/listinfo/tcl-core
|
|
From: Florent M. <flo...@gm...> - 2026-04-23 14:12:51
|
<ADVERT> Just try it : https://github.com/florentis/tcl90-exprSH/tree/core-9-0-branch/install_SH </ADVERT> Le 23/04/2026 à 11:36, Poor Yorick a écrit : > Here is it is: > > proc = args { > lmap item $args[set args {}] {uplevel 1 [list ::expr $item]} > } > > Example: > > .canvas addtag enclosed {*}[= {$x-20} {$x+20} {$y-20} {$y+20}] > .canvas addtag enclosed {*}[($x-20, $x+20, $y-20, $y+20)] ! no double substitution ! ! no table of command pollution ! ! no problem when renaming '=' ! ! no problem with lexical scope ! ! no problem with execution frame ! > > If that isn't efficient enough, then making the necessary to changes > to Tcl to > make it more efficient would be a good direction. > > But I would call that something like lexpr so that = could be used to > make expr > more convenient: > > proc = args { > uplevel 1 [join [lmap {varname expr} $args[set args {}] { > lindex "::set [list $varname] \[::expr [list $expr]]" > }] \n] > } > > Example: > > = x {3 * 3.14} y {$x * 2} > In command parsing context (muted expression substitution) : [(x = 3*3.14; y = $x*2;)] In expression parsing context : x = 3*3.14; y = $x*2; ! no double substitution ! ! no table of command pollution ! ! no problem when renaming '=' ! ! no problem with lexical scope ! ! no problem with execution frame ! > Those two procedures make doing math in Tcl pretty reasonable, without > any > language modification. > Using expr language is not doing any language modification. There is allready two parsing context : * The command parsing context * The expression parsing context Both parsing are following different principles, which are not fully compatible. All what we can do is to make possible to pass values (as var, or as script), from one context to another context. Let's make the "expression parsing context" more accessible from the "command parsing context". In command parsing context, let's have : eval { command [( expression; )] command [( expression; )] command [( expression; )] } In expression parsing context, let's have : expr { expression; [ command ]; expression; [ command ]; expression; [ command ]; } <ADVERT> Just try it : https://github.com/florentis/tcl90-exprSH/tree/core-9-0-branch/install_SH </ADVERT> Regards, Florent |
|
From: Florent M. <flo...@gm...> - 2026-04-23 13:41:02
|
Hi Martin, Peter, Community,
Code impact is only 259 lines of code.
2 enums , 4 C-array updated, 11 functions modified, in 4 files.
It is not much. It's not immense as you assert.
It's very little for the effect !
Here is a summary of the changes :
kind / part Subst Script TIP282 List Total (kind)
new lines 75 55 51 24 205
line changed 1 0 2 2 5
line space / comment 15 13 13 8 49
Total (part) 91 68 66 34 259
NB : Each "part" is one part of the Proposal :
* Subst is for '[( ... )]' shorthand expression substitution
* Script is for script substitution (ex : eval (1+1) ; proc P {} {( ...
)}; if {...} then (0) else "($res)" ; ...etc)
* TIP 282 is for SEPARATOR and ASSIGNEMENT : 'expr {a = 1; b = 2}'
* List is for list handling : 'expr {(1, 2, 3, 4)}'
You'll find an Excel File in attachement for more details.
[ Notice that I removed the most problematic part (substitution of array
index) :
It appears that an index can be parsed in the middle of execution. As
to compute an index with expr, I needed to compile bytecodes, it was not
doable.]
I respect your opinion, but, I think you didn't try the implementation.
There may be some misunderstanding.
Myself, I could load a big package tcllib::math, nothing was complaining.
Of course, lot of tests have to be made.
I recieved opinions, more encouraging than yours :
AMB wrote in the Wiki yesterday (ref
https://wiki.tcl-lang.org/page/A+Better+way+to+do+calculations)
--------------------------------------------------
*AMB <https://wiki.tcl-lang.org/page/AMB> - 2026-04-22 19:47:30*
I downloaded your prototype, FM <https://wiki.tcl-lang.org/page/FM>, and
it's great!!
-----------------------------------------------------------------
Ok, he would like to allow spaces before and after the parentheses. We
could use Tcl_ParseWhiteSpace for this, but It must be discussed.
I prefer to have something that look like a two-char symbol `[(` `{(`
`"(`. But, in console context, why not ?
Whatever. Now there is a prototype.
Before any new change, it's better everybody can play with this
prototype and comment it.
My time is counted also, that's why I count on the community feedback.
I 'm proposing you to try the prototype first (for windows, statically
compiled with gcc, under mingwin).
You'll find it at :
https://github.com/florentis/tcl90-exprSH/tree/core-9-0-branch/install_SH
The actual version of the TIP text, which must be improved, can be found
at :
https://github.com/florentis/tcl90-exprSH/blob/core-9-0-branch/TIP_Expr_Shorthand.md
Then you can give an opinion founded on facts, not on what it may be, at
the view of a long mailing list discussion.
Regards, Tchüss,
Florent
Le 22/04/2026 à 23:27, Martin Lemburg a écrit :
> Reading all the content provided by you, Florent, my gut feeling about
> not wanting those changes gets louder, stronger.
> The changes let us win some simplicity in using mathmatics everywhere.
> The costs are imense, since basic things changes like you just described.
> Additionally, the costs of changes in several parts of the tcl sources
> and probably introduced bugs (no one develops in a complex environment
> without introducing bugs) encourage my gut to shake his head, mourning
> "no, no, no".
> To introduce a new command with a "new" little language only for
> mathmathics is one (quite discussable) thing - not changing parts of
> tcl parser.
> The changes you propose are much wider/deeper in their consequences
> and the longer I think of them the more I think, that they are too
> risky and that they go too far.
> Best regards
> Martin Lemburg
> Berlin / Germany
>
> mar...@gm...
> *Gesendet: *Mittwoch, 22. April 2026 um 22:19
> *Von: *"Florent Merlet" <flo...@gm...>
> *An: *"da Silva, Peter J" <pet...@fl...>,
> "tcl...@li..." <tcl...@li...>
> *Betreff: *Re: [TCLCORE] Variation on the Expr Shorthand
> Le 22/04/2026 à 16:50, da Silva, Peter J a écrit :
>
> OK:
> % proc ( {args} { puts "( $args" }
> % ( hello )
> ( hello )
> This is legal existing syntax.
>
> Hi Peter,
>
> It's still legal, but the meaning is different : it makes '(' a
> meaningfull symbol in some context.
>
> If you want a '(' proc, it would then be like it is now with '[' proc,
> '{' proc or {"} proc :
> You would have to protect it with backslah when you call it.
> Like it is now :
>
> % \( hello )
> ( hello )
> % set a [\( hello )]
> ( hello )
> % proc A {} {\( hello )}
> % A
> ( hello )
>
> There is clearly a choice to be made.
>
> Is it acceptable to be forced to add an extra backslah to call the "("
> proc,
> just to gain at least 4 chars for each expression used in a script ?
>
> My opinion is "yes", it is very acceptable, because I never use any
> "(" proc, and because I'm fade up writing things like :
>
> set a [expr {...}]
> set b [expr {...}]
>
> Without hesitation, I prefer to write :
>
> [(a = ...; b = ...;)]
>
> Even in including some non essential whitespace for clarity, the last
> is only 21 chars, whereas the first is 36 chars.
> So, I can still call the "(" proc 15 times, whithout any loss.
>
> My deep opinion is even it would be unacceptable to not accept it.
>
> But I would understand it exists other opinions.
>
> Regards
>
> *From: *Florent Merlet <flo...@gm...>
> <mailto:flo...@gm...>
> *Date: *Wednesday, April 22, 2026 at 06:41
> *To: *da Silva, Peter J (USA) <pet...@fl...>
> <mailto:pet...@fl...>;
> tcl...@li... <tcl...@li...>
> <mailto:tcl...@li...>
> *Subject: *Re: [TCLCORE] Variation on the Expr Shorthand
>
> CAUTION - EXTERNAL EMAIL:
> This message originated from outside of your organization. Do not
> click links or open attachments unless you recognize the sender
> and know the content is safe.
> Le 29/10/2025 à 15:56, da Silva, Peter J a écrit :
>
> That has the same problem of breaking existing syntax.
> % proc ( {args} { puts $args }
> % ( hello
> hello
>
>
> Hi Peter,
>
> No, It doesn't : check ->
> https://github.com/florentis/tcl90-exprSH/tree/core-9-0-branch/install_SH/bin
> <https://urldefense.us/v2/url?u=https-3A__github.com_florentis_tcl90-2DexprSH_tree_core-2D9-2D0-2Dbranch_install-5FSH_bin&d=DwMDaQ&c=MASr1KIcYm9UGIT-jfIzwQg1YBeAkaJoBtxV_4o83uQ&r=BRyGRggIJd8TmKOhvEmGElFuDuCl3O5mT8opva3f-Uc&m=w2tfEZJ11k3zrwJuBQ24gT2PBdBoy0rWTxoFVW7mf-Wmbu-TPHMsSUmUoCydsS8B&s=TQbNb_jQH5uxu4bjbvHKXOCChssskqh-ohkPZULZRnI&e=>
>
>
> I) In *console wish context* :
> a) No closed paren -> _proc_
> (bin) 4 % ( hello
> hello
> -> ie : The last argument must finish with a ')'
>
> b) First char = open paren, last char = closed paren -> _expression_
> 5 % ( hello )
> invalid bareword "hello"
> in expression "( hello )
> ";
> should be "$hello" or "{hello}" or "hello(...)" or ...
>
> -> If ever, add a space before the open parenthese or after the
> close parenthese.
>
> c) First char = open paren, last char = space -> _proc_
> 6 % ( hello ) ;
> hello
>
> d) First char = space, last char = close paren -> _proc_
> 7 % ( hello )
> hello )
>
> II) In *script context*, it's also true :
> a) No closed paren
> (bin) 8 % proc A {} {( hello}
> (bin) 9 % A
> hello
>
> b) First char = open paren, last char = closed paren -> _expression_
> (bin) 10 % proc B {} {( hello )}
> (bin) 11 % B
> invalid bareword "hello"
> in expression "( hello )";
> should be "$hello" or "{hello}" or "hello(...)" or ...
>
> c) First char = open paren, last char = space -> _proc_
> (bin) 12 % proc C {} {( hello ) }
> (bin) 13 % C
> hello )
>
> d) First char = space, last char = closed paren -> _proc_
> (bin) 14 % proc D {} { ( hello)}
> (bin) 15 % D
> hello)
>
> III) In *substitution context*, I have to implement it when coming
> back from expr with parsing error, to get the same effect.
> I think it's doable.
>
> a) No closed paren : -> expression/ (to be corrected, should be
> proc)/
> (bin) 16 % set A [( hello ]
> invalid bareword "hello"
> in expression "( hello ]
> ";
> should be "$hello" or "{hello}" or "hello(...)" or ...
>
> b) first char = open paren, last char = close paren -> expression.
> (bin) 17 % set B [( hello )]
> invalid bareword "hello"
> in expression "( hello )]
> ";
> should be "$hello" or "{hello}" or "hello(...)" or ...
>
> c) First char = space, , last char = close paren -> proc
> (bin) 18 % set C [ ( hello )]
> hello )
>
> d) first char = open paren, last char = space -> expression /(to
> be corrected, should be proc)/
> (bin) 16 % set D [( hello ) ]
> invalid bareword "hello"
> in expression "( hello ) ]
> ";
> should be "$hello" or "{hello}" or "hello(...)" or ...
>
> Regards
>
>
> *From: *Florent Merlet <flo...@gm...>
> <mailto:flo...@gm...>
> *Date: *Wednesday, October 29, 2025 at 09:45
> *To: *tcl...@li...
> <tcl...@li...>
> <mailto:tcl...@li...>
> *Subject: *[TCLCORE] Variation on the Expr Shorthand
>
> CAUTION - EXTERNAL EMAIL:
> This message originated from outside of your organization. Do
> not click links or open attachments unless you recognize the
> sender and know the content is safe.
>
> Hi dear Tcl community,
>
> An Expr shorthand syntax has been a long time demand between us.
>
> Those discussions always focus on the syntax aspect of the
> subject :
>
> * Like in bash $(...) or $((...))
> * Through an alias [= ...]
> * A new command (vexpr or let)
> * A word prefix {=}
> * ...
>
> A lot of TIPs exists on that matter. Numerous discussions
> occurs, which never ended to get a consensus.
>
> That's because the look of this shorthand is a matter of
> taste. Everybody has his own taste. Some people like fish when
> it's cooked in water, some people like it when it's fried.
> Some people even don't like fish at all ! Every taste is in
> the nature.
>
> Everybody can agree that Tcl is a big and complex machinery,
> that must be handled with care. So maybe the problem must be
> taken the other way round :
>
> * Shall we deduce the Tcl C source code machinery from a new
> syntax, we had previously decided (the one doesn't make
> consensus)
> * Or shall we deduce the new syntax from the Tcl C source
> code machinery, as it exists ?
>
> My opinion is that it's better to deduce the syntax from the
> Tcl C source code, rather than to deduce the Tcl source C code
> from the syntax .
>
> TIP 672 is hacking the variable substitution. To do this, it
> has to make a very basic parsing of the expression to estimate
> its length. It has to transmute a TCL_VARIABLE Token into a
> TCL_COMMAND token. It then use a call to Tcl_ParseCommand on a
> synthetic string to check errors.
>
> This very basic parsing will make it buggy. For instance, a
> shorthand expression can't be nested in another one. A quote
> inside braces would create an error. To make this parsing
> strong, we would have to reinvent all the expression parsing
> from scratch.
>
> But shall we create a new parsing expression routine for this
> shorthand ? No, there exist already an expression parsing
> machinery, that can handle words between Quotes or Braces and
> can handle Nested Commands, exactly how the Expr command do.
>
> « Deduce the shorthand syntax from the Tcl C source Code »
> imply to find a syntax which allows us to use the existing
> machinery.
>
> That's what I'm trying now :
>
> As Expr is a command in Tcl, it seems logical to me to
> implement the shorthand syntax in the Command branch "[" of
> parseToken procedure. That's what I choosed.
>
> The second step is to parse the expression, so to go through
> Tcl_ParseExpr routine, then to the ParseExpr routine. The
> difficulty here is to get the end of the substitution script
> in the ParseExpr routine. If I don't want to disturb parseExpr
> too much, it's better to choose, as character which ends the
> expression script, a character that is significant for this
> parser, so the main task of detecting it is already done, but
> can be adapted gently.
>
> Maybe I could have used any of those operators : '+', '=',
> '-', '*', '(', ')', '|',...etc. But I choosed to use ')' :
> infix language needs parenthesis.
>
> That is how I defined the end of the expression substitution
> script to be ")]". By symetry, I defined the beginning of the
> substitution script to be "[(".
>
> Here is the genesis of my proposal of "[( ...)]" as a shorthand.
>
> To make it work, I had to used the same clever hacking than
> Eric Taylor : create a synthethic string and parse it as a
> command.
>
> At the end, the [(...)] is working as expected (so far I've
> tested). Here are the main changes I have done to accomplish it :
>
> In file Tcl_Parse.c : in function parseTokens, I add a new
> branch in the test
>
> ----------------------------------------
>
> ... } else if (src[0] == '[' && src[1] == '(') {
> ///////////////////////////////////////////////////////////////////////
>
> /* Expression substition context */
> // to do : noSubstExpr
> Tcl_Parse *exprParsePtr;
> exprParsePtr =(Tcl_Parse
> *)TclStackAlloc(parsePtr->interp, sizeof(Tcl_Parse));
>
> src++; // src == '['
> numBytes --;
> // Use it only to know the length of the expression,
> and store it into exprParsePtr->commandSize
> Tcl_ParseExpr(parsePtr->interp, src, numBytes,
> exprParsePtr);
>
> src++; // src == '('
> numBytes --;
>
> // Here is the famous hack of Eric Taylor
> Tcl_Size syntheticLen = exprParsePtr->commandSize +
> 9; // "[expr {" + expr + "}]"
>
> char *synthetic = (char *)Tcl_Alloc(syntheticLen + 1);
>
> memcpy(synthetic, "[expr {", 7);
> memcpy(synthetic + 7, src, exprParsePtr->commandSize);
>
> memcpy(synthetic + 7 + exprParsePtr->commandSize,
> "}]", 3);
> synthetic[syntheticLen] = '\0';
> // Maybe a Tcl_Obj could be of use for memory
> management ?
>
> Tcl_Obj *exprObjCommand =
> Tcl_NewStringObj(synthetic,syntheticLen);
>
> src+=exprParsePtr->commandSize+2;
> numBytes-=exprParsePtr->commandSize+2;
>
> TclStackFree(parsePtr->interp, exprParsePtr);
>
> tokenPtr->type = TCL_TOKEN_COMMAND;
> tokenPtr->start = Tcl_GetStringFromObj(exprObjCommand,
> NULL);
> tokenPtr->size = syntheticLen;
> parsePtr->numTokens++;
>
> continue;
>
> } else if (*src == '[') {...
>
> ---------------------------------------
>
> To detect the end and transfer the size of the parsed
> expression I had to modify :
>
> 1° the Tcl_ParseExpr function :
>
> ... if (code == TCL_OK) {
> if(start[-1] == '[' && start[0] == '(' ) {
> // Expression Substitution Context : just transfer the
> size information to the caller
> parsePtr->commandSize =exprParsePtr->commandSize;
> } else {
> TclParseInit(interp, start, numBytes, parsePtr);
> ConvertTreeToTokens(start, numBytes,
> opTree, exprParsePtr->tokenPtr, parsePtr);
> } ...
>
> 2° the ParseExpr fonction
>
> int nb_paren=0;
> int substExpressionContext=0;
>
> if(start[-1] == '[' && start[0] == '(' ) {
> substExpressionContext=1;
>
> // Expression substitution
> start++; //skip the open parenthesis '(' : it's part of
> the expression substitution syntax
> numBytes--;
> }
>
> ...
>
> case UNARY:
>
> //////////////////////////////////
>
> if (substExpressionContext == 1) {
>
> // Beyond binary operators, there is Open paren,
> count it
>
> if (start[0]== '(') {
>
> // Count the open parenthesis in this context
>
> nb_paren++;
> }
> }
>
> case BINARY: {
> ...
> if (substExpressionContext == 1) {
>
> // Beyond binary operators, there is closed Paren,
> count it.
>
> if (start[0] == ')') {
> nb_paren--;
> if (nb_paren == -1 && start[1] ==']') {
> //// End of expression
> parsePtr->commandSize = originalLength -
> numBytes - 1;
> numBytes=0;
> continue; // and exit the loop, since
> numbytes == 0 ;)
> }
> }
> }
>
> ----------------------------------------
>
> I add also make it nestable, ie : set x [(1 + [(2+3)] )]
>
> in the function Parse_Expr :
>
> case SCRIPT : {
>
> ...
>
> if (start[1] == '(') {
>
> // an open braket followed by an open paren is
> denoting the expression shorthand
>
> tokenPtr->type = TCL_TOKEN_SUB_EXPR;
> } else {
> tokenPtr->type = TCL_TOKEN_COMMAND;
> }
>
> ...
>
> In the function TclCompileTokens (file tclCompile.c), I add :
>
> case TCL_TOKEN_SUB_EXPR :
> envPtr->line += adjust;
> TclCompileExpr(interp, tokenPtr->start+1,
> tokenPtr->size-2, envPtr, 0);
> envPtr->line -= adjust;
> numObjsToConcat++;
>
> break;
>
> ---------------------
>
> Then, I can write :
>
> % set x [(1+1)]
>
> 2
>
> % set y [($x + [(1 + 1)] )]
>
> 4
>
> % set z [($y + [($x * [(1+1)] )] )]
>
> 8
>
> -----------------------------
>
> Surely there is corner cases that this prototype doesn't
> resolve. More investigations are needed and it should be
> extensively tested, but this prove that the [(...)] expression
> shorthand is possible at little cost. Maybe even the
> TCL_TOKEN_SUB_EXPR Token could be used instead of creating a
> synthetic string. I may investigate this las option later...
>
> Florent
>
> _______________________________________________ Tcl-Core mailing list
> Tcl...@li...
> https://lists.sourceforge.net/lists/listinfo/tcl-core
--
<center>
<hr/>
<b>Florent MERLET</b><br/>
<i>4 rue Johann Strauss<br/>
Logement 7<br/>
86180 BUXEROLLES</i><br/>
<hr/>
<b>Mél.</b> : <i>flo...@gm...</i><br/>
<b>Tél.</b> : <i>06 70 00 63 48</i>
</center>
|
|
From: Poor Y. <org...@po...> - 2026-04-23 09:36:15
|
On 2026-04-23 11:28, EricT wrote:
> Hi Poor,
>
> Can you elaborate on your = helper here?
>
> Is this something that takes each argument and passes it on to expr,
> and
> then returns a list of results? If so, can you pass it to expr braced
> so it
> compiles efficiently?
>
> Regards,
>
> Eric
Here is it is:
proc = args {
lmap item $args[set args {}] {uplevel 1 [list ::expr $item]}
}
Example:
.canvas addtag enclosed {*}[= {$x-20} {$x+20} {$y-20} {$y+20}]
If that isn't efficient enough, then making the necessary to changes to
Tcl to
make it more efficient would be a good direction.
But I would call that something like lexpr so that = could be used to
make expr
more convenient:
proc = args {
uplevel 1 [join [lmap {varname expr} $args[set args {}] {
lindex "::set [list $varname] \[::expr [list $expr]]"
}] \n]
}
Example:
= x {3 * 3.14} y {$x * 2}
Those two procedures make doing math in Tcl pretty reasonable, without
any
language modification.
--
Yorick
|
|
From: EricT <tw...@gm...> - 2026-04-23 08:29:08
|
Hi Poor,
Can you elaborate on your = helper here?
Is this something that takes each argument and passes it on to expr, and
then returns a list of results? If so, can you pass it to expr braced so it
compiles efficiently?
Regards,
Eric
On Wed, Apr 22, 2026 at 11:20 PM Poor Yorick <
org...@po...> wrote:
> On 2026-04-23 08:36, Harald Oehlmann wrote:
> > Am 23.04.2026 um 02:00 schrieb Steve Landers:
> >> YES: SL, KW, HO,
> >>
> >> NO: DF, AK, RA
> >>
> >> PRESENT: AN, MC
> >>
> >> The YES vote doesn't meet the two-thirds threshold and so the TIP is
> >> not accepted. Thanks for all who contributed, especially to Colin
> >> Macleod for the effort he invested.
> >>
> >> -- Steve
>
> It's good that this TIP didn't pass. It's already trivial to create a
> procedure that is nearly as concise without any language change:
>
> .canvas addtag enclosed {*}[= {$x-20} {$x+20} {$y-20} {$y+20}]
>
> What worries me is that the TIP only got 3 NO votes.
>
> --
> Yorick
>
>
>
> _______________________________________________
> Tcl-Core mailing list
> Tcl...@li...
> https://lists.sourceforge.net/lists/listinfo/tcl-core
>
|
|
From: Poor Y. <org...@po...> - 2026-04-23 06:20:16
|
On 2026-04-23 08:36, Harald Oehlmann wrote:
> Am 23.04.2026 um 02:00 schrieb Steve Landers:
>> YES: SL, KW, HO,
>>
>> NO: DF, AK, RA
>>
>> PRESENT: AN, MC
>>
>> The YES vote doesn't meet the two-thirds threshold and so the TIP is
>> not accepted. Thanks for all who contributed, especially to Colin
>> Macleod for the effort he invested.
>>
>> -- Steve
It's good that this TIP didn't pass. It's already trivial to create a
procedure that is nearly as concise without any language change:
.canvas addtag enclosed {*}[= {$x-20} {$x+20} {$y-20} {$y+20}]
What worries me is that the TIP only got 3 NO votes.
--
Yorick
|
|
From: Harald O. <har...@el...> - 2026-04-23 05:37:15
|
Am 23.04.2026 um 02:00 schrieb Steve Landers: > YES: SL, KW, HO, > > NO: DF, AK, RA > > PRESENT: AN, MC > > The YES vote doesn't meet the two-thirds threshold and so the TIP is not > accepted. Thanks for all who contributed, especially to Colin Macleod > for the effort he invested. > > -- Steve I am sorry for this result. I want to send my appreciation to all those people who have invested many many hours and thoughts into this. I personally see no clue out of the dilemma how to make expr & friends more intuitive. Thanks, Harald |
|
From: Harald O. <har...@el...> - 2026-04-23 05:25:12
|
For me, it would be ok to include this command in tcl core and to make "package require registry" a dummy. Many other core commands require it. Thanks, Harald Am 22.04.2026 um 18:01 schrieb apnmbx-public--- via Tcl-Core: > Makes sense. Have gone that route with registry aliased to tcl::registry > on a package require. Init code that accesses the registry then need not > pull in “registry” into the global namespace. > > *From:*Donal Fellows <don...@ma...> > *Sent:* Tuesday, April 21, 2026 9:56 PM > *To:* 'Tcl Core List' <tcl...@li...>; apnmbx- > pu...@ya... > *Subject:* Re: [TCLCORE] Including registry.dll in tcl.dll > > I think you're OK to just do it, though for compatibility you could put > the permanent command under *::tcl* and have the *package ifneeded* > script alias that into the global namespace. Anyone using the existing > command usage won't see the difference (except by looking at the list of > aliases). > > Donal. > > ------------------------------------------------------------------------ > > *From:* apnmbx-public--- via Tcl-Core <tcl...@li... > <mailto:tcl...@li...>> > *Sent:* Tuesday, April 21, 2026 17:20 > *To:* 'Tcl Core List' <tcl...@li... <mailto:tcl- > co...@li...>> > *Subject:* [TCLCORE] Including registry.dll in tcl.dll > > Would anyone object to subsuming registry.dll within tcl.dll even in > shared builds? It would only add some 20KB to a 3MB DLL so that’s not an > issue. > > Motivation is fixing some Windows tickets that require access to > registry and this would both simplify (registry command) and avoid code > duplication. > > And then the 64K USD question – does this require a TIP? The documented > interfaces don’t change so I would say no. But happy to write a TIP if > folks are happy to vote on one more :-) > > /Ashok > > > > _______________________________________________ > Tcl-Core mailing list > Tcl...@li... > https://lists.sourceforge.net/lists/listinfo/tcl-core -- ELMICRON Dr. Harald Oehlmann GmbH Koesener Str. 85 06618 NAUMBURG - Germany Phone: +49 3445 781120 Direct: +49 3445 781127 www.Elmicron.de German legal references: Geschaeftsfuehrer: Dr. Harald Oehlmann UST Nr. / VAT ID No.: DE206105272 HRB 212803 Stendal |
|
From: Steve L. <st...@di...> - 2026-04-23 00:49:04
|
TIP #750: YES -- Steve On 22 Apr 2026 at 3:43 PM +0800, Harald Oehlmann <har...@el...>, wrote: > this is a call for vote for TIP 750 "wm attribtue $w apearance dark" |
|
From: Steve L. <st...@di...> - 2026-04-23 00:00:27
|
YES: SL, KW, HO, NO: DF, AK, RA PRESENT: AN, MC The YES vote doesn't meet the two-thirds threshold and so the TIP is not accepted. Thanks for all who contributed, especially to Colin Macleod for the effort he invested. -- Steve |
|
From: Martin L. <mar...@gm...> - 2026-04-22 21:27:19
|
<html><body><div style="font-family: 'verdana'; font-size: 12px; color: #000;">Reading all the content provided by you, Florent, my gut feeling about not wanting those changes gets louder, stronger.</div>
<div style="font-family: 'verdana'; font-size: 12px; color: #000;"> </div>
<div style="font-family: 'verdana'; font-size: 12px; color: #000;">The changes let us win some simplicity in using mathmatics everywhere.</div>
<div style="font-family: 'verdana'; font-size: 12px; color: #000;">The costs are imense, since basic things changes like you just described.</div>
<div style="font-family: 'verdana'; font-size: 12px; color: #000;"> </div>
<div style="font-family: 'verdana'; font-size: 12px; color: #000;">Additionally, the costs of changes in several parts of the tcl sources and probably introduced bugs (no one develops in a complex environment without introducing bugs) encourage my gut to shake his head, mourning "no, no, no".</div>
<div style="font-family: 'verdana'; font-size: 12px; color: #000;"> </div>
<div style="font-family: 'verdana'; font-size: 12px; color: #000;">To introduce a new command with a "new" little language only for mathmathics is one (quite discussable) thing - not changing parts of tcl parser.</div>
<div style="font-family: 'verdana'; font-size: 12px; color: #000;">The changes you propose are much wider/deeper in their consequences and the longer I think of them the more I think, that they are too risky and that they go too far.</div>
<div style="font-family: 'verdana'; font-size: 12px; color: #000;"> </div>
<div style="font-family: 'verdana'; font-size: 12px; color: #000;">Best regards</div>
<div style="font-family: 'verdana'; font-size: 12px; color: #000;"> </div>
<div id="signature-container" style="background-color: #ffffff; font-size: 12px; font-family: verdana; color: #000000;">Martin Lemburg<br>Berlin / Germany<br><br>mar...@gm...</div>
<div id="sub-body-container" style="margin: 10px 5px 5px 10px; padding: 10px 0px 10px 10px; border-left: 2px solid rgb(195, 217, 229);">
<div style="margin: 0px 0px 10px;">
<div><strong>Gesendet: </strong>Mittwoch, 22. April 2026 um 22:19</div>
<div><strong>Von: </strong>"Florent Merlet" <flo...@gm...></div>
<div><strong>An: </strong>"da Silva, Peter J" <pet...@fl...>, "tcl...@li..." <tcl...@li...></div>
<div><strong>Betreff: </strong>Re: [TCLCORE] Variation on the Expr Shorthand</div>
</div>
<div>Le 22/04/2026 à 16:50, da Silva, Peter J a écrit : </div>
<blockquote>
<div style="direction: ltr; font-family: Aptos , Arial , Helvetica , sans-serif; font-size: 12.0pt; color: #000000;">OK:</div>
<div style="direction: ltr; font-family: Aptos , Arial , Helvetica , sans-serif; font-size: 12.0pt; color: #000000;"> </div>
<div style="direction: ltr; font-family: Aptos , Arial , Helvetica , sans-serif; font-size: 12.0pt; color: #000000;"> % proc ( {args} { puts "( $args" }</div>
<div style="font-family: Aptos , Arial , Helvetica , sans-serif; font-size: 12.0pt; color: #000000;"> % ( hello )</div>
<div style="font-family: Aptos , Arial , Helvetica , sans-serif; font-size: 12.0pt; color: #000000;"> ( hello )</div>
<div style="direction: ltr; font-family: Aptos , Arial , Helvetica , sans-serif; font-size: 12.0pt; color: #000000;"> </div>
<div style="font-family: Aptos , Arial , Helvetica , sans-serif; font-size: 12.0pt; color: #000000;">This is legal existing syntax.</div>
<div style="direction: ltr; font-family: Aptos , Arial , Helvetica , sans-serif; font-size: 12.0pt; color: #000000;"> </div>
</blockquote>
Hi Peter, <br><br>It's still legal, but the meaning is different : it makes '(' a meaningfull symbol in some context. <br><br>If you want a '(' proc, it would then be like it is now with '[' proc, '{' proc or {"} proc : <br>You would have to protect it with backslah when you call it. <br>Like it is now : <br><br><span style="font-family: monospace;">% \( hello ) <br>( hello ) <br>% set a [\( hello )] <br>( hello ) <br>% proc A {} {\( hello )} <br>% A <br>( hello )</span> <br><br>There is clearly a choice to be made. <br><br>Is it acceptable to be forced to add an extra backslah to call the "(" proc, <br>just to gain at least 4 chars for each expression used in a script ? <br><br>My opinion is "yes", it is very acceptable, because I never use any "(" proc, and because I'm fade up writing things like : <br><br><span style="font-family: monospace;">set a [expr {...}] <br>set b [expr {...}] <br><br></span>Without hesitation, I prefer to write : <br><br><span style="font-family: monospace;">[(a = ...; b = ...;)] <br><br></span>Even in including some non essential whitespace for clarity, the last is only 21 chars, whereas the first is 36 chars. <br>So, I can still call the "(" proc 15 times, whithout any loss. <br><br>My deep opinion is even it would be unacceptable to not accept it. <br><br>But I would understand it exists other opinions. <br><br>Regards
<blockquote>
<div style="direction: ltr; font-family: Aptos , Arial , Helvetica , sans-serif; font-size: 12.0pt; color: #000000;"> </div>
<div id="mail-editor-reference-message-container">
<div style="direction: ltr;"> </div>
<div style="padding: 3.0pt 0 0; border-width: 1.0pt medium medium; border-style: solid none none;">
<div style="text-align: left; font-family: Aptos; font-size: 12.0pt; color: black;"><strong>From: </strong>Florent Merlet <a href="mailto:flo...@gm..." target="_blank" rel="noopener noreferrer"><flo...@gm...></a> <br><strong>Date: </strong>Wednesday, April 22, 2026 at 06:41 <br><strong>To: </strong>da Silva, Peter J (USA) <a href="mailto:pet...@fl..." target="_blank" rel="noopener noreferrer"><pet...@fl...></a>; <a href="mailto:tcl...@li..." target="_blank" rel="noopener noreferrer">tcl...@li...</a> <a href="mailto:tcl...@li..." target="_blank" rel="noopener noreferrer"><tcl...@li...></a> <br><strong>Subject: </strong>Re: [TCLCORE] Variation on the Expr Shorthand <br><br></div>
</div>
<div id="pfptBannerswdau7n" lang="en" style="visibility: visible !important; max-width: none !important; max-height: none !important; display: block !important; text-align: left !important; margin: 16.0px 0 !important; padding: 8.0px 16.0px !important; border-radius: 4.0px !important; min-width: 200.0px !important; background-color: #ffffff; border-top-width: 4.0px !important; border-top-style: solid !important; border-top-color: rgb(187,187,187) !important;">
<div id="pfptBannerswdau7n" style="visibility: visible !important; background-color: #ffffff; max-height: none !important; float: left !important; display: block !important; margin: 0 0 1.0px !important; max-width: 600.0px !important;">
<div id="pfptBannerswdau7n" style="max-width: none !important; max-height: none !important; display: block !important; visibility: visible !important; background-color: #ffffff; color: #000000; font-family: Arial , sans-serif !important; font-weight: bold !important; font-size: 14.0px !important; line-height: 18.0px !important;">CAUTION - EXTERNAL EMAIL:</div>
<div id="pfptBannerswdau7n" style="font-weight: normal; max-width: none !important; max-height: none !important; display: block !important; visibility: visible !important; background-color: #ffffff; color: #000000; font-family: Arial , sans-serif !important; font-size: 12.0px !important; line-height: 18.0px !important; margin-top: 2.0px !important;">This message originated from outside of your organization. Do not click links or open attachments unless you recognize the sender and know the content is safe.</div>
</div>
<div style="line-height: 0; clear: both; height: 0; display: block; font-size: 0.01px;"> </div>
</div>
<div>Le 29/10/2025 à 15:56, da Silva, Peter J a écrit :</div>
<blockquote>
<div style="direction: ltr; font-family: Aptos , Arial , Helvetica , sans-serif; font-size: 12.0pt; color: #000000;">That has the same problem of breaking existing syntax.</div>
<div style="direction: ltr; font-family: Aptos , Arial , Helvetica , sans-serif; font-size: 12.0pt; color: #000000;"> </div>
<div style="direction: ltr; font-family: Aptos , Arial , Helvetica , sans-serif; font-size: 12.0pt; color: #000000;"> % proc ( {args} { puts $args }</div>
<div style="font-family: Aptos , Arial , Helvetica , sans-serif; font-size: 12.0pt; color: #000000;"> % ( hello</div>
<div style="font-family: Aptos , Arial , Helvetica , sans-serif; font-size: 12.0pt; color: #000000;"> hello</div>
</blockquote>
<div><br>Hi Peter, <br><br>No, It doesn't : check -> <a href="https://urldefense.us/v2/url?u=https-3A__github.com_florentis_tcl90-2DexprSH_tree_core-2D9-2D0-2Dbranch_install-5FSH_bin&d=DwMDaQ&c=MASr1KIcYm9UGIT-jfIzwQg1YBeAkaJoBtxV_4o83uQ&r=BRyGRggIJd8TmKOhvEmGElFuDuCl3O5mT8opva3f-Uc&m=w2tfEZJ11k3zrwJuBQ24gT2PBdBoy0rWTxoFVW7mf-Wmbu-TPHMsSUmUoCydsS8B&s=TQbNb_jQH5uxu4bjbvHKXOCChssskqh-ohkPZULZRnI&e=" target="_blank" rel="noopener noreferrer" data-href="https://urldefense.us/v2/url?u=https-3A__github.com_florentis_tcl90-2DexprSH_tree_core-2D9-2D0-2Dbranch_install-5FSH_bin&d=DwMDaQ&c=MASr1KIcYm9UGIT-jfIzwQg1YBeAkaJoBtxV_4o83uQ&r=BRyGRggIJd8TmKOhvEmGElFuDuCl3O5mT8opva3f-Uc&m=w2tfEZJ11k3zrwJuBQ24gT2PBdBoy0rWTxoFVW7mf-Wmbu-TPHMsSUmUoCydsS8B&s=TQbNb_jQH5uxu4bjbvHKXOCChssskqh-ohkPZULZRnI&e="> https://github.com/florentis/tcl90-exprSH/tree/core-9-0-branch/install_SH/bin</a> <br><br>I) In <strong>console wish context</strong> : <br>a) No closed paren -> <u>proc</u> <br><span style="font-family: monospace;">(bin) 4 % ( hello <br>hello</span> <br>-> ie : The last argument must finish with a ')' <br><br>b) First char = open paren, last char = closed paren -> <u>expression</u> <br><span style="font-family: monospace;">5 % ( hello ) <br>invalid bareword "hello" <br>in expression "( hello ) <br>"; <br>should be "$hello" or "{hello}" or "hello(...)" or ...</span> <br><br>-> If ever, add a space before the open parenthese or after the close parenthese. <br><br>c) First char = open paren, last char = space -> <u>proc</u> <br><span style="font-family: monospace;">6 % ( hello ) ; <br>hello</span> <br><br>d) First char = space, last char = close paren -> <u>proc</u> <br><span style="font-family: monospace;">7 % ( hello ) <br>hello )</span> <br><br>II) In <strong>script context</strong>, it's also true : <br>a) No closed paren <br><span style="font-family: monospace;">(bin) 8 % proc A {} {( hello} <br>(bin) 9 % A <br>hello <br></span> <br>b) First char = open paren, last char = closed paren -> <u>expression</u> <br><span style="font-family: monospace;">(bin) 10 % proc B {} {( hello )} <br>(bin) 11 % B <br>invalid bareword "hello" <br>in expression "( hello )"; <br>should be "$hello" or "{hello}" or "hello(...)" or ...</span> <br><br>c) First char = open paren, last char = space -> <u>proc</u> <br><span style="font-family: monospace;">(bin) 12 % proc C {} {( hello ) } <br>(bin) 13 % C <br>hello )</span> <br><br>d) First char = space, last char = closed paren -> <u>proc</u> <br><span style="font-family: monospace;">(bin) 14 % proc D {} { ( hello)} <br>(bin) 15 % D <br>hello)</span> <br><br>III) In <strong>substitution context</strong>, I have to implement it when coming back from expr with parsing error, to get the same effect. <br>I think it's doable. <br><br>a) No closed paren : -> expression<em> (to be corrected, should be proc)</em> <br><span style="font-family: monospace;">(bin) 16 % set A [( hello ] <br>invalid bareword "hello" <br>in expression "( hello ] <br>"; <br>should be "$hello" or "{hello}" or "hello(...)" or ...</span> <br><br>b) first char = open paren, last char = close paren -> expression. <br><span style="font-family: monospace;">(bin) 17 % set B [( hello )] <br>invalid bareword "hello" <br>in expression "( hello )] <br>"; <br>should be "$hello" or "{hello}" or "hello(...)" or ... <br><br></span>c) First char = space, , last char = close paren -> proc <br><span style="font-family: monospace;">(bin) 18 % set C [ ( hello )] <br>hello )</span> <br><br>d) first char = open paren, last char = space -> expression <em>(to be corrected, should be proc)</em> <br><span style="font-family: monospace;">(bin) 16 % set D [( hello ) ] <br>invalid bareword "hello" <br>in expression "( hello ) ] <br>"; <br>should be "$hello" or "{hello}" or "hello(...)" or ...</span> <br><br>Regards <br><br><br></div>
<blockquote>
<div style="direction: ltr; font-family: Aptos , Arial , Helvetica , sans-serif; font-size: 12.0pt; color: #000000;"> </div>
<div id="mail-editor-reference-message-container">
<div style="text-align: left; padding: 3.0pt 0 0; border-width: 1.0pt medium medium; border-style: solid none none; font-family: Aptos; font-size: 12.0pt; color: black;"><strong>From: </strong>Florent Merlet <a href="mailto:flo...@gm..." target="_blank" rel="noopener noreferrer"> <flo...@gm...></a> <br><strong>Date: </strong>Wednesday, October 29, 2025 at 09:45 <br><strong>To: </strong><a href="mailto:tcl...@li..." target="_blank" rel="noopener noreferrer">tcl...@li...</a> <a href="mailto:tcl...@li..." target="_blank" rel="noopener noreferrer"> <tcl...@li...></a> <br><strong>Subject: </strong>[TCLCORE] Variation on the Expr Shorthand <br><br></div>
<div id="pfptBannerghzljzn" lang="en" style="visibility: visible !important; max-width: none !important; max-height: none !important; display: block !important; text-align: left !important; margin: 16.0px 0 !important; padding: 8.0px 16.0px !important; border-radius: 4.0px !important; min-width: 200.0px !important; background-color: #ffffff; border-top-width: 4.0px !important; border-top-style: solid !important; border-top-color: rgb(187,187,187) !important;">
<div id="pfptBannerghzljzn" style="visibility: visible !important; background-color: #ffffff; max-height: none !important; float: left !important; display: block !important; margin: 0 0 1.0px !important; max-width: 600.0px !important;">
<div id="pfptBannerghzljzn" style="max-width: none !important; max-height: none !important; display: block !important; visibility: visible !important; background-color: #ffffff; color: #000000; font-family: Arial , sans-serif !important; font-weight: bold !important; font-size: 14.0px !important; line-height: 18.0px !important;">CAUTION - EXTERNAL EMAIL:</div>
<div id="pfptBannerghzljzn" style="font-weight: normal; max-width: none !important; max-height: none !important; display: block !important; visibility: visible !important; background-color: #ffffff; color: #000000; font-family: Arial , sans-serif !important; font-size: 12.0px !important; line-height: 18.0px !important; margin-top: 2.0px !important;">This message originated from outside of your organization. Do not click links or open attachments unless you recognize the sender and know the content is safe.</div>
</div>
<div style="line-height: 0; height: 0; display: block; font-size: 0.01px;"> </div>
</div>
<p>Hi dear Tcl community,</p>
<p>An Expr shorthand syntax has been a long time demand between us.</p>
<p>Those discussions always focus on the syntax aspect of the subject : </p>
<ul>
<li>Like in bash $(...) or $((...))</li>
<li>Through an alias [= ...]</li>
<li>A new command (vexpr or let)</li>
<li>A word prefix {=}</li>
<li>...</li>
</ul>
<p>A lot of TIPs exists on that matter. Numerous discussions occurs, which never ended to get a consensus.</p>
<p>That's because the look of this shorthand is a matter of taste. Everybody has his own taste. Some people like fish when it's cooked in water, some people like it when it's fried. Some people even don't like fish at all ! Every taste is in the nature. </p>
<p>Everybody can agree that Tcl is a big and complex machinery, that must be handled with care. So maybe the problem must be taken the other way round :</p>
<ul>
<li>Shall we deduce the Tcl C source code machinery from a new syntax, we had previously decided (the one doesn't make consensus)</li>
<li>Or shall we deduce the new syntax from the Tcl C source code machinery, as it exists ?</li>
</ul>
<p>My opinion is that it's better to deduce the syntax from the Tcl C source code, rather than to deduce the Tcl source C code from the syntax .</p>
<p>TIP 672 is hacking the variable substitution. To do this, it has to make a very basic parsing of the expression to estimate its length. It has to transmute a TCL_VARIABLE Token into a TCL_COMMAND token. It then use a call to Tcl_ParseCommand on a synthetic string to check errors.</p>
<p>This very basic parsing will make it buggy. For instance, a shorthand expression can't be nested in another one. A quote inside braces would create an error. To make this parsing strong, we would have to reinvent all the expression parsing from scratch. </p>
<p>But shall we create a new parsing expression routine for this shorthand ? No, there exist already an expression parsing machinery, that can handle words between Quotes or Braces and can handle Nested Commands, exactly how the Expr command do. </p>
<p>« Deduce the shorthand syntax from the Tcl C source Code » imply to find a syntax which allows us to use the existing machinery.</p>
<p>That's what I'm trying now :</p>
<p>As Expr is a command in Tcl, it seems logical to me to implement the shorthand syntax in the Command branch "[" of parseToken procedure. That's what I choosed.</p>
<p>The second step is to parse the expression, so to go through Tcl_ParseExpr routine, then to the ParseExpr routine. The difficulty here is to get the end of the substitution script in the ParseExpr routine. If I don't want to disturb parseExpr too much, it's better to choose, as character which ends the expression script, a character that is significant for this parser, so the main task of detecting it is already done, but can be adapted gently.</p>
<p>Maybe I could have used any of those operators : '+', '=', '-', '*', '(', ')', '|',...etc. But I choosed to use ')' : infix language needs parenthesis.</p>
<p>That is how I defined the end of the expression substitution script to be ")]". By symetry, I defined the beginning of the substitution script to be "[(".</p>
<p>Here is the genesis of my proposal of "[( ...)]" as a shorthand. </p>
<p>To make it work, I had to used the same clever hacking than Eric Taylor : create a synthethic string and parse it as a command. </p>
<p>At the end, the [(...)] is working as expected (so far I've tested). Here are the main changes I have done to accomplish it :</p>
<p>In file Tcl_Parse.c : in function parseTokens, I add a new branch in the test</p>
<p>----------------------------------------</p>
<p> ... } else if (src[0] == '[' && src[1] == '(') { <br> /////////////////////////////////////////////////////////////////////// <br> /* Expression substition context */ <br> // to do : noSubstExpr <br> Tcl_Parse *exprParsePtr; <br> exprParsePtr =(Tcl_Parse *)TclStackAlloc(parsePtr->interp, sizeof(Tcl_Parse)); <br> <br> src++; // src == '[' <br> numBytes --; <br> // Use it only to know the length of the expression, and store it into exprParsePtr->commandSize <br> Tcl_ParseExpr(parsePtr->interp, src, numBytes, exprParsePtr); <br> <br> src++; // src == '(' <br> numBytes --;</p>
<p> // Here is the famous hack of Eric Taylor <br> Tcl_Size syntheticLen = exprParsePtr->commandSize + 9; // "[expr {" + expr + "}]" <br> <br> char *synthetic = (char *)Tcl_Alloc(syntheticLen + 1); <br> <br> memcpy(synthetic, "[expr {", 7); <br> memcpy(synthetic + 7, src, exprParsePtr->commandSize);</p>
<p> memcpy(synthetic + 7 + exprParsePtr->commandSize, "}]", 3); <br> synthetic[syntheticLen] = '\0'; <br> // Maybe a Tcl_Obj could be of use for memory management ? </p>
<p> Tcl_Obj *exprObjCommand = Tcl_NewStringObj(synthetic,syntheticLen);</p>
<p> src+=exprParsePtr->commandSize+2; <br> numBytes-=exprParsePtr->commandSize+2; <br><br> TclStackFree(parsePtr->interp, exprParsePtr); <br> <br> tokenPtr->type = TCL_TOKEN_COMMAND; <br> tokenPtr->start = Tcl_GetStringFromObj(exprObjCommand, NULL); <br> tokenPtr->size = syntheticLen; <br> parsePtr->numTokens++; <br><br> continue;</p>
<p>} else if (*src == '[') {...</p>
<p>---------------------------------------</p>
<p>To detect the end and transfer the size of the parsed expression I had to modify :</p>
<p>1° the Tcl_ParseExpr function :</p>
<p>... if (code == TCL_OK) { <br> if(start[-1] == '[' && start[0] == '(' ) { <br> // Expression Substitution Context : just transfer the size information to the caller <br> parsePtr->commandSize =exprParsePtr->commandSize; <br> } else { <br> TclParseInit(interp, start, numBytes, parsePtr); <br> ConvertTreeToTokens(start, numBytes, <br> opTree, exprParsePtr->tokenPtr, parsePtr); <br> } ...</p>
<p>2° the ParseExpr fonction</p>
<p>int nb_paren=0; <br>int substExpressionContext=0;</p>
<p>if(start[-1] == '[' && start[0] == '(' ) { <br> substExpressionContext=1; <br><br> // Expression substitution <br> start++; //skip the open parenthesis '(' : it's part of the expression substitution syntax <br> numBytes--; <br>}</p>
<p>... <span style="font-family: monospace;"> </span></p>
<p>case UNARY:</p>
<p> //////////////////////////////////</p>
<p> if (substExpressionContext == 1) {</p>
<p> // Beyond binary operators, there is Open paren, count it</p>
<p> if (start[0]== '(') {</p>
<p> // Count the open parenthesis in this context</p>
<p> nb_paren++; <br> } <br> }</p>
<p>case BINARY: { <br> ... <br> if (substExpressionContext == 1) {</p>
<p> // Beyond binary operators, there is closed Paren, count it.</p>
<p> if (start[0] == ')') { <br> nb_paren--; <br> if (nb_paren == -1 && start[1] ==']') { <br> //// End of expression <br> parsePtr->commandSize = originalLength - numBytes - 1; <br> numBytes=0; <br> continue; // and exit the loop, since numbytes == 0 ;) <br> } <br> } <br> }</p>
<p>----------------------------------------</p>
<p>I add also make it nestable, ie : set x [(1 + [(2+3)] )] </p>
<p>in the function Parse_Expr :</p>
<p>case SCRIPT : {</p>
<p>...</p>
<p> if (start[1] == '(') {</p>
<p> // an open braket followed by an open paren is denoting the expression shorthand</p>
<p> tokenPtr->type = TCL_TOKEN_SUB_EXPR; <br> } else { <br> tokenPtr->type = TCL_TOKEN_COMMAND; <br> }</p>
<p>...</p>
<p>In the function TclCompileTokens (file tclCompile.c), I add :</p>
<p>case TCL_TOKEN_SUB_EXPR : <br> envPtr->line += adjust; <br> TclCompileExpr(interp, tokenPtr->start+1, tokenPtr->size-2, envPtr, 0); <br> envPtr->line -= adjust; <br> numObjsToConcat++; </p>
<p> break;</p>
<p>---------------------</p>
<p>Then, I can write : </p>
<p>% set x [(1+1)]</p>
<p>2</p>
<p>% set y [($x + [(1 + 1)] )]</p>
<p>4</p>
<p>% set z [($y + [($x * [(1+1)] )] )]</p>
<p>8</p>
<p>-----------------------------</p>
<p>Surely there is corner cases that this prototype doesn't resolve. More investigations are needed and it should be extensively tested, but this prove that the [(...)] expression shorthand is possible at little cost. Maybe even the TCL_TOKEN_SUB_EXPR Token could be used instead of creating a synthetic string. I may investigate this las option later...</p>
<p>Florent</p>
</div>
</blockquote>
</div>
</blockquote>
_______________________________________________ Tcl-Core mailing list Tcl...@li... https://lists.sourceforge.net/lists/listinfo/tcl-core</div></body></html>
|
|
From: Marc C. <cul...@gm...> - 2026-04-22 21:06:40
|
So if I have two commits how can I tell if they are in the same branch? - Marc On Wed, Apr 22, 2026, 3:58 PM Andreas Kupries <and...@gm...> wrote: > > From the article, Fossil is quite happy to have multiple different > branches > > with the same name. > > Absolutely. For example, see `mistake` in the fossil repo itself. > > https://fossil-scm.org/home/timeline?r=mistake > > And also > > https://fossil-scm.org/home/doc/tip/www/branching.wiki#unique > > Last section at the bottom of the page. > > > Phil > > > > On Wed, Apr 22, 2026 at 12:39 PM Marc Culler <cul...@gm...> wrote: > > > > > I think the fact that it is not possible for different branches to have > > > the same name is a tautology. The name is what defines the branch. > > Not in fossil. > > > But it > > > is definitely possible for a branch to have more than one leaf. That > is a > > > fork, and must be avoided. > > > > > > - Marc > > > > >>> https://core.tcl-lang.org/tk/timeline?r=pbrooks-nmakehlp-exe-removal > > >>> > > >>> you can see all commits in the branch, which begin with that one. It > > >>> looks perfectly normal to me. I think the confusion is is caused by > the > > >>> fact that in the graph of the full timeline when you view that > commit the > > >>> web browser window is not big enough to show the second commit. So > you > > >>> just see an arrow emitting from the green dot, not connected to > anything > > >>> else on the page. > > >>> > > >>> > > >>> > > >>> I don't think it is possible to have two branches with the same name. > > > Happy Tcling, > Andreas Kupries <and...@gm...> > <https://core.tcl-lang.org/akupries/> > <https://akupries.tclers.tk/> > Developer @ SUSE Software Solutions Germany GmbH > > ------------------------------------------------------------------------------- > > > |