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
(320) |
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
|
From: Marc C. <cul...@gm...> - 2026-04-24 22:16:53
|
I have just pushed a change to the implementation of TIP 750, and I will shortly update the text of the TIP. Those who have already voted need to be aware of this. The change is that the implementation now fully supports the "auto" value for the appearance attribute of a toplevel on Windows. Specifically: 1) The default value of the appearance attribute is now "auto". 2) When a new toplevel is created (with appearance "auto") it will be displayed with the light or dark theme as specified by the AppsUseLightTheme Registry variable, which can be set from the system Settings app. 3) When the value of that setting is changed, all "auto" toplevels will be re-rendered with the new choice of theme. For example, if the user has a tool like "Light Switch" that automatically changes to dark mode at a certain time, all "auto" toplevels will switch to having black title bars when the change occurs. 4} A toplevel with appearance "light" or "dark" has opted to override the system setting, and it will not change color when the Settings variable toggles between light and dark. 5) When an "auto" toplevel changes theme as a result of a change to the value of AppsUseLightTheme, e.g. by choosing "dark" in the Settings, it will receive a virtual event <<AppearanceChanged>> with data string "appearance light" or "appearance dark" as appropriate for the new theme. This should allow a Tk app to support dark mode in its window content by changing the color palette within the binding script for that virtual event. I anticipate that someday more fields will be added to the data string, for example specifying accent colors. But this TIP only relates to the light and dark themes. Emiliano has kindly tested the latest version on Windows 10 and reports that it works. I have tested on Windows 11 with the same report. - Marc |
|
From: <av...@lo...> - 2026-04-24 21:53:06
|
Now at least 11 ;-) See you in ... uhm ... Bologna ... > We are looking forward to meeting you in Bologna. > > Many thanks, > The Organization Committee ... seems like a relict from last year (in the welcome Mail after reg). Not yet sure about doing a short talk, maybe, if slots are still vacant lateron... -- avl Am 2026-04-24 11:42, schrieb Harald Oehlmann: > Dear Tcl/Tk team members, > > The OpenACS/TCL/Tk user meeting in Vienna 16/17th of July 2026 will > take place. We just had the wrap-up call. 10 people registered, mainly > from Tcl/Tk side. So, the critical mass is reached. > > https://openacs.km.at > > It is a community meeting. Each participant is motivated to show its > work in a small presentation. And we will have the panels about > Tcl/Tk/Naviserver/OpenACS. > The location is the same great cosy room at the University of Economics > as in 2024. > Newcomers are also invited. Helpful people and information will be > there! > > So, feel welcomed to the great meeting. > > See you in July in Vienna! > > Gustaf, Stefan and Harald > > _______________________________________________ > Tcl-Core mailing list > Tcl...@li... > https://lists.sourceforge.net/lists/listinfo/tcl-core |
|
From: B H. <bra...@gm...> - 2026-04-24 19:28:53
|
Hello Tclers. I've been working in Tk, specifically w image, and would like run a proposal passed Core. In struct Tk_ImageType, generic/tk.h L1257 there is a "char *reserved", which was last updated by Brent Welch nearly 30 (c. 1998) years ago, is semantically marked as a placeholder for some future expansion, and as far as i can tell, not actually referenced anywhere. Proposal: can we take this and formally give it to developers as a ClientData clientData entry in the struct? As far as i can tell, it would functionally be a documentation update, not breaking any public APIs or ABIs. Best, -bch |
|
From: EricT <tw...@gm...> - 2026-04-24 13:50:41
|
Yes, you are right about the drawback to using tcl::unsupported::assemble.
That is certainly the Achilles heel of my little Calc project. But I'm only
in it for the subs and likes, anyway. However, I do notice I have 0
followers and 0 likes on my github page😭
It will likely be quite difficult to get that assembler made public. On the
other hand, it sure seems like a waste of 4400 lines of great code, not to
mention another 1600 lines or so in the disassembly.
I'm not sure if vecTCL would benefit or not, but that was also mentioned in
the telco.
Now that the frenzy is dying down, how about you. Did you really debug your
code just using printf? You should have plenty of time now getting VS 2026
installed and then you would see how super their debugger for C is. I used
it to find the code that was doing pointer arithmetic across tokens that
caused my $(...) code to crash. I can't imagine finding that with just
printf.
Anyway, good luck with your project.
Eric
On Fri, Apr 24, 2026 at 3:39 AM Florent Merlet <flo...@gm...>
wrote:
> Hi Eric,
> I ve noticed at bytecodes analysis that inst_invoke_stk has a cost while
> building list.
>
> The correction is to create a "LIST" lexeme, to set it instead of FUNC,
> then emit the list bytecodes inst while compiling the tree.
> Then I can remove this list FUNC from table of math FUNC. I was planning
> to do it.
>
> But, this is a question of optimisation, that can be seen later, if ever
> the proposal become a TIP.
>
> Build : I saw a TIP about encoding and wish.exe.manifest.in, from Ashok.
> Surely he can say something about this.
> I must clean tclVar.c. There is no change in this file, since i dismissed
> array index expr shorthand.
>
> You are saying you follow this direction, because you want it to be
> independant from the core. But, finally, you have to ask for a core change,
> because it would be too slow without bytecodes compilation.
>
> So in fact, you can't be independant from the core, also.
>
> Yes, the possibility to generate bytecodes could serve many purposes (and
> my proposal is still on the table) but the core team people said, they want
> to be free to refactor it if they need to.
>
> If you rely on it, you may loose compatibility at any time. That would be
> a problem also.
>
> So, your proposal, done to be "independant from the core" is shown to be
> "dependant on the core", in a contradiction with your initial intention.
>
> Maybe the only solution for you is to produce native code ? Would it be
> possible with critcl ?
>
> Regards,
> Florent.
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
> Le ven. 24 avr. 2026, 11:16, EricT <tw...@gm...> a écrit :
>
>> Hi Florent,
>>
>> On your three points:
>>
>> 1. The timerate example -- timerate is a development and benchmarking tool, not production code. And actually the [: ...] inline form does not need to start on its own line at all, so the side by side comparison is straightforward:
>>
>> proc= test {x y} {
>> puts orig:[timerate {list [expr {$x-10}] [expr {$x+20}] [expr {$y-20}] [expr {$y+20}]}]
>> puts colon:[timerate {[: list(x-10,x+20,y-20,y+20)]}]
>> }
>>
>> The : standalone statement form does need to be on its own line, which is a deliberate tradeoff -- no full Tcl parser, no surgery on the existing one, no TIP, no requiring consensus from programmers all over the world. Completely optional -- if one person uses it, everyone else is entirely unaffected.
>>
>> 2. Of course proc= adds a new command -- it is a module, not a core change. Every package ever written adds new commands. The real question is whether those commands require a TIP and core team consensus, and mine do not.
>>
>> But I notice your approach also adds a new command -- list as a mathfunc in BuiltinFuncDef. Unlike proc= which is optional and only affects those who load the module, your list addition is a permanent core modification that affects every Tcl program. And it is slower -- your list(1,2,3) generates:
>>
>> push "tcl::mathfunc::list"
>> invokeStk n
>>
>> whereas my list() generates the direct list bytecode instruction -- no push of a fully qualified name, no command dispatch at all. The core modification buys you worse performance.
>>
>> 3. Your inline flexibility with for, foreach, if, switch, eval is a genuine advantage of your approach. But the transformation cost of proc= is negligible and happens only once at program startup when the procs are defined -- much like sourcing any Tcl file, or namespace eval which evaluates a script in a particular context. Nobody argues that namespace eval is a bad pattern because it requires wrapping code in a block.
>>
>> Also, my module works in 8.6 and 9.x now. I don't have to build tcl from a modified source.
>>
>> BTW, I can't run your static wish/tclsh exe's because I don't have the compiler you use.
>>
>> I was unable to get your tk to build something about a wish.exe.manifest.in. Also, you had an unused variable "len" in TclLookupArrayElement which tripped the warnings are errors on my build. After fixing that I could run your code in tclsh.
>>
>>
>> Best regards,
>> Eric
>>
>>
>>
>> On Fri, Apr 24, 2026 at 12:27 AM Florent Merlet <
>> flo...@gm...> wrote:
>>
>>> Ok.
>>>
>>> Notice that my proposal doesn't need any new command named 'proc='.
>>>
>>> I can just do :
>>> proc test {x y} {
>>> puts orig:[timerate {list [ .... ]}]
>>> puts shorthand:[timerate {( ... )}]
>>> }
>>> to compare two bytecodes.
>>>
>>> can you do this with your proposal ?
>>>
>>> proc test {x y} {
>>> puts orig:[timerate {list [ .... ]}]
>>> puts colon:[timerate {: ... }]
>>> }
>>>
>>>
>>> If i want to compile a whole proc as expression, i can do :
>>>
>>> proc p args {( ... )}
>>>
>>> How will you get this effect with your proposal ?
>>>
>>> proc p args {: { ... }}
>>> proc= p args { ... }
>>>
>>> The last one is 1 char shorther, but need a new command.
>>>
>>> With my proposal, you can do :
>>> eval {( .... )}
>>> for {( .... )} {....} {( .... )} {( .... )}
>>> If { } then {( .... )} else {( .... )}
>>> Switch $a { case {( .... )} default {( .... )} }
>>> Foreach i $L {( .... )}
>>> Lmap j $K {( .... )}
>>> ... Etc
>>> And get it bytecompiled with the expression parser where there is
>>> parenthesis.
>>>
>>> Can your proposal do this ?
>>>
>>> Regards,
>>> Florent
>>>
>>>
>>>
>>> Le ven. 24 avr. 2026, 07:42, EricT <tw...@gm...> a écrit :
>>>
>>>> Hi Florent,
>>>>
>>>> The ugliness of my test case was simply my uncertainty about how timerate works. After Serg's clarification I realized that transform= can handle : inside a timerate block as long as the : command starts on its own line. My transform= is not a full Tcl parser -- it uses 5 or 6 regexps and doesn't count brace nesting levels -- so I accept that compromise. Here is the cleaner test Serg suggested:
>>>>
>>>> % proc= test {x y} {
>>>> timerate {
>>>> : list(x-10,x+20,y-20,y+20)
>>>> }
>>>> }
>>>> % test 5 20
>>>> 0.260845 µs/# 3833681 #/sec 999.997 net-ms
>>>>
>>>> % proc test2 {x y} {
>>>> timerate {
>>>> list [expr {$x-10}] [expr {$x+20}] [expr {$y-20}] [expr {$y+20}]
>>>> }
>>>> }
>>>> % test2 5 10
>>>> 0.253317 µs/# 3947624 #/sec 1000.000 net-ms
>>>>
>>>> Essentially identical -- and the disassembly confirms why: both produce exactly the same bytecode.
>>>>
>>>> As for why I used an infix expression compiler rather than extending expr -- two reasons. First, Colin had already written a beautiful pure Tcl Pratt parser that I could build on immediately. Second, at the time I had no understanding of how bytecode and the assembler worked, so using Colin's compiler as a front end to generate TAL was the obvious path. It turned out to be a fortunate choice since it required no core changes at all.
>>>>
>>>> Regarding your bytecode interface proposal -- I think you may be underestimating the scope of what tclAssembly.c actually does. The parser touch points you list are just the entry points. The 4400 lines handle label resolution, stack depth verification, LVT management, exception range tracking, operand encoding, and error reporting for 130+ opcodes. That infrastructure already exists and works -- which is exactly why I am arguing for a public interface to it rather than new parser syntax on top of it.
>>>>
>>>> Best regards,
>>>> Eric
>>>>
>>>>
>>>>
>>>>
>>>>
>>>> On Thu, Apr 23, 2026 at 9:53 PM Florent Merlet <
>>>> flo...@gm...> wrote:
>>>>
>>>>> 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
>>>>> _______________________________________________
>>>>> 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: Kevin W. <kw...@co...> - 2026-04-24 13:23:47
|
Hi Harald, On 4/24/26 7:41 AM, Harald Oehlmann wrote: > thanks for all the work, this is highly appreciated. > I suppose, that the branch rtl_text is ready for testing: > > https://core.tcl-lang.org/tk/timeline?r=rtl_text&c=2026-04-23+12%3A05%3A22 > Almost. I am reviewing the test failures to determine what the issues might be. I don't want to cause regressions with bidi text in addressing the test failures - looking into the test suite is part of making sure the bidi changes are as stable as I can make them. One known bug that I can't fix - CJK text spacing is still too tight in the text widget when mixed with other encodings (Latin/RTL). > > It is only about the text widget, right? Correct. > > It would be great to give other experts a week of time to digest. > Christian and Csaba understand the internals, Jan and Emiliano are > also in. Maybe, they may comment. Agree - when I am satisfied it is as stable as I can make it, I want as much input as possible. > > The test failures may come later IMHO. Of cause, it is important. > But I would prefer first a comment by other experts, if they agree > with the proposed change. See above. > > I would really love to have this feature in 9.1. We don't need a TIP. > But it is for sure a breaking feature which solves a long standing > miss-functioning. As I have recently observed with font and rotation, > bug fixes may create new bugs found years after... > > If it may be the default on Linux: "yes of cause", says the Windows > guy. AFAI understood, there are new dependencies to the "harfbuzz" > library. So, the question is, if this dependency is ok. > Con't we test by the configure script, if this dependency is ok? > Some distribution people? Reinhard? As part of testing, I will set up configure to make bidi the default on X11 - so simply running "configure" will activate both bidi and Xft. Harfbuzz is not a niche library, it is as widely installed as dbus or Xlib, so I don't believe it will present an issue. But let's see what others think. I'll send out a formal invitation for testing soon. > > Thanks for all and take care, > Harald > Thank you, Kevin -- Kevin Walzer kw...@co... |
|
From: Harald O. <har...@el...> - 2026-04-24 11:41:32
|
Dear Kevin, thanks for all the work, this is highly appreciated. I suppose, that the branch rtl_text is ready for testing: https://core.tcl-lang.org/tk/timeline?r=rtl_text&c=2026-04-23+12%3A05%3A22 It is only about the text widget, right? It would be great to give other experts a week of time to digest. Christian and Csaba understand the internals, Jan and Emiliano are also in. Maybe, they may comment. The test failures may come later IMHO. Of cause, it is important. But I would prefer first a comment by other experts, if they agree with the proposed change. I would really love to have this feature in 9.1. We don't need a TIP. But it is for sure a breaking feature which solves a long standing miss-functioning. As I have recently observed with font and rotation, bug fixes may create new bugs found years after... If it may be the default on Linux: "yes of cause", says the Windows guy. AFAI understood, there are new dependencies to the "harfbuzz" library. So, the question is, if this dependency is ok. Con't we test by the configure script, if this dependency is ok? Some distribution people? Reinhard? Thanks for all and take care, Harald Am 24.04.2026 um 02:50 schrieb Kevin Walzer: > 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 > |
|
From: Florent M. <flo...@gm...> - 2026-04-24 10:38:52
|
Hi Eric,
I ve noticed at bytecodes analysis that inst_invoke_stk has a cost while
building list.
The correction is to create a "LIST" lexeme, to set it instead of FUNC,
then emit the list bytecodes inst while compiling the tree.
Then I can remove this list FUNC from table of math FUNC. I was planning to
do it.
But, this is a question of optimisation, that can be seen later, if ever
the proposal become a TIP.
Build : I saw a TIP about encoding and wish.exe.manifest.in, from Ashok.
Surely he can say something about this.
I must clean tclVar.c. There is no change in this file, since i dismissed
array index expr shorthand.
You are saying you follow this direction, because you want it to be
independant from the core. But, finally, you have to ask for a core change,
because it would be too slow without bytecodes compilation.
So in fact, you can't be independant from the core, also.
Yes, the possibility to generate bytecodes could serve many purposes (and
my proposal is still on the table) but the core team people said, they want
to be free to refactor it if they need to.
If you rely on it, you may loose compatibility at any time. That would be a
problem also.
So, your proposal, done to be "independant from the core" is shown to be
"dependant on the core", in a contradiction with your initial intention.
Maybe the only solution for you is to produce native code ? Would it be
possible with critcl ?
Regards,
Florent.
Le ven. 24 avr. 2026, 11:16, EricT <tw...@gm...> a écrit :
> Hi Florent,
>
> On your three points:
>
> 1. The timerate example -- timerate is a development and benchmarking tool, not production code. And actually the [: ...] inline form does not need to start on its own line at all, so the side by side comparison is straightforward:
>
> proc= test {x y} {
> puts orig:[timerate {list [expr {$x-10}] [expr {$x+20}] [expr {$y-20}] [expr {$y+20}]}]
> puts colon:[timerate {[: list(x-10,x+20,y-20,y+20)]}]
> }
>
> The : standalone statement form does need to be on its own line, which is a deliberate tradeoff -- no full Tcl parser, no surgery on the existing one, no TIP, no requiring consensus from programmers all over the world. Completely optional -- if one person uses it, everyone else is entirely unaffected.
>
> 2. Of course proc= adds a new command -- it is a module, not a core change. Every package ever written adds new commands. The real question is whether those commands require a TIP and core team consensus, and mine do not.
>
> But I notice your approach also adds a new command -- list as a mathfunc in BuiltinFuncDef. Unlike proc= which is optional and only affects those who load the module, your list addition is a permanent core modification that affects every Tcl program. And it is slower -- your list(1,2,3) generates:
>
> push "tcl::mathfunc::list"
> invokeStk n
>
> whereas my list() generates the direct list bytecode instruction -- no push of a fully qualified name, no command dispatch at all. The core modification buys you worse performance.
>
> 3. Your inline flexibility with for, foreach, if, switch, eval is a genuine advantage of your approach. But the transformation cost of proc= is negligible and happens only once at program startup when the procs are defined -- much like sourcing any Tcl file, or namespace eval which evaluates a script in a particular context. Nobody argues that namespace eval is a bad pattern because it requires wrapping code in a block.
>
> Also, my module works in 8.6 and 9.x now. I don't have to build tcl from a modified source.
>
> BTW, I can't run your static wish/tclsh exe's because I don't have the compiler you use.
>
> I was unable to get your tk to build something about a wish.exe.manifest.in. Also, you had an unused variable "len" in TclLookupArrayElement which tripped the warnings are errors on my build. After fixing that I could run your code in tclsh.
>
>
> Best regards,
> Eric
>
>
>
> On Fri, Apr 24, 2026 at 12:27 AM Florent Merlet <flo...@gm...>
> wrote:
>
>> Ok.
>>
>> Notice that my proposal doesn't need any new command named 'proc='.
>>
>> I can just do :
>> proc test {x y} {
>> puts orig:[timerate {list [ .... ]}]
>> puts shorthand:[timerate {( ... )}]
>> }
>> to compare two bytecodes.
>>
>> can you do this with your proposal ?
>>
>> proc test {x y} {
>> puts orig:[timerate {list [ .... ]}]
>> puts colon:[timerate {: ... }]
>> }
>>
>>
>> If i want to compile a whole proc as expression, i can do :
>>
>> proc p args {( ... )}
>>
>> How will you get this effect with your proposal ?
>>
>> proc p args {: { ... }}
>> proc= p args { ... }
>>
>> The last one is 1 char shorther, but need a new command.
>>
>> With my proposal, you can do :
>> eval {( .... )}
>> for {( .... )} {....} {( .... )} {( .... )}
>> If { } then {( .... )} else {( .... )}
>> Switch $a { case {( .... )} default {( .... )} }
>> Foreach i $L {( .... )}
>> Lmap j $K {( .... )}
>> ... Etc
>> And get it bytecompiled with the expression parser where there is
>> parenthesis.
>>
>> Can your proposal do this ?
>>
>> Regards,
>> Florent
>>
>>
>>
>> Le ven. 24 avr. 2026, 07:42, EricT <tw...@gm...> a écrit :
>>
>>> Hi Florent,
>>>
>>> The ugliness of my test case was simply my uncertainty about how timerate works. After Serg's clarification I realized that transform= can handle : inside a timerate block as long as the : command starts on its own line. My transform= is not a full Tcl parser -- it uses 5 or 6 regexps and doesn't count brace nesting levels -- so I accept that compromise. Here is the cleaner test Serg suggested:
>>>
>>> % proc= test {x y} {
>>> timerate {
>>> : list(x-10,x+20,y-20,y+20)
>>> }
>>> }
>>> % test 5 20
>>> 0.260845 µs/# 3833681 #/sec 999.997 net-ms
>>>
>>> % proc test2 {x y} {
>>> timerate {
>>> list [expr {$x-10}] [expr {$x+20}] [expr {$y-20}] [expr {$y+20}]
>>> }
>>> }
>>> % test2 5 10
>>> 0.253317 µs/# 3947624 #/sec 1000.000 net-ms
>>>
>>> Essentially identical -- and the disassembly confirms why: both produce exactly the same bytecode.
>>>
>>> As for why I used an infix expression compiler rather than extending expr -- two reasons. First, Colin had already written a beautiful pure Tcl Pratt parser that I could build on immediately. Second, at the time I had no understanding of how bytecode and the assembler worked, so using Colin's compiler as a front end to generate TAL was the obvious path. It turned out to be a fortunate choice since it required no core changes at all.
>>>
>>> Regarding your bytecode interface proposal -- I think you may be underestimating the scope of what tclAssembly.c actually does. The parser touch points you list are just the entry points. The 4400 lines handle label resolution, stack depth verification, LVT management, exception range tracking, operand encoding, and error reporting for 130+ opcodes. That infrastructure already exists and works -- which is exactly why I am arguing for a public interface to it rather than new parser syntax on top of it.
>>>
>>> Best regards,
>>> Eric
>>>
>>>
>>>
>>>
>>>
>>> On Thu, Apr 23, 2026 at 9:53 PM Florent Merlet <
>>> flo...@gm...> wrote:
>>>
>>>> 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
>>>> _______________________________________________
>>>> 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: Harald O. <har...@el...> - 2026-04-24 09:43:08
|
Dear Tcl/Tk team members, The OpenACS/TCL/Tk user meeting in Vienna 16/17th of July 2026 will take place. We just had the wrap-up call. 10 people registered, mainly from Tcl/Tk side. So, the critical mass is reached. https://openacs.km.at It is a community meeting. Each participant is motivated to show its work in a small presentation. And we will have the panels about Tcl/Tk/Naviserver/OpenACS. The location is the same great cosy room at the University of Economics as in 2024. Newcomers are also invited. Helpful people and information will be there! So, feel welcomed to the great meeting. See you in July in Vienna! Gustaf, Stefan and Harald |
|
From: EricT <tw...@gm...> - 2026-04-24 09:16:23
|
Hi Florent,
On your three points:
1. The timerate example -- timerate is a development and benchmarking
tool, not production code. And actually the [: ...] inline form does
not need to start on its own line at all, so the side by side
comparison is straightforward:
proc= test {x y} {
puts orig:[timerate {list [expr {$x-10}] [expr {$x+20}] [expr
{$y-20}] [expr {$y+20}]}]
puts colon:[timerate {[: list(x-10,x+20,y-20,y+20)]}]
}
The : standalone statement form does need to be on its own line, which
is a deliberate tradeoff -- no full Tcl parser, no surgery on the
existing one, no TIP, no requiring consensus from programmers all over
the world. Completely optional -- if one person uses it, everyone else
is entirely unaffected.
2. Of course proc= adds a new command -- it is a module, not a core
change. Every package ever written adds new commands. The real
question is whether those commands require a TIP and core team
consensus, and mine do not.
But I notice your approach also adds a new command -- list as a
mathfunc in BuiltinFuncDef. Unlike proc= which is optional and only
affects those who load the module, your list addition is a permanent
core modification that affects every Tcl program. And it is slower --
your list(1,2,3) generates:
push "tcl::mathfunc::list"
invokeStk n
whereas my list() generates the direct list bytecode instruction -- no
push of a fully qualified name, no command dispatch at all. The core
modification buys you worse performance.
3. Your inline flexibility with for, foreach, if, switch, eval is a
genuine advantage of your approach. But the transformation cost of
proc= is negligible and happens only once at program startup when the
procs are defined -- much like sourcing any Tcl file, or namespace
eval which evaluates a script in a particular context. Nobody argues
that namespace eval is a bad pattern because it requires wrapping code
in a block.
Also, my module works in 8.6 and 9.x now. I don't have to build tcl
from a modified source.
BTW, I can't run your static wish/tclsh exe's because I don't have the
compiler you use.
I was unable to get your tk to build something about a
wish.exe.manifest.in. Also, you had an unused variable "len" in
TclLookupArrayElement which tripped the warnings are errors on my
build. After fixing that I could run your code in tclsh.
Best regards,
Eric
On Fri, Apr 24, 2026 at 12:27 AM Florent Merlet <flo...@gm...>
wrote:
> Ok.
>
> Notice that my proposal doesn't need any new command named 'proc='.
>
> I can just do :
> proc test {x y} {
> puts orig:[timerate {list [ .... ]}]
> puts shorthand:[timerate {( ... )}]
> }
> to compare two bytecodes.
>
> can you do this with your proposal ?
>
> proc test {x y} {
> puts orig:[timerate {list [ .... ]}]
> puts colon:[timerate {: ... }]
> }
>
>
> If i want to compile a whole proc as expression, i can do :
>
> proc p args {( ... )}
>
> How will you get this effect with your proposal ?
>
> proc p args {: { ... }}
> proc= p args { ... }
>
> The last one is 1 char shorther, but need a new command.
>
> With my proposal, you can do :
> eval {( .... )}
> for {( .... )} {....} {( .... )} {( .... )}
> If { } then {( .... )} else {( .... )}
> Switch $a { case {( .... )} default {( .... )} }
> Foreach i $L {( .... )}
> Lmap j $K {( .... )}
> ... Etc
> And get it bytecompiled with the expression parser where there is
> parenthesis.
>
> Can your proposal do this ?
>
> Regards,
> Florent
>
>
>
> Le ven. 24 avr. 2026, 07:42, EricT <tw...@gm...> a écrit :
>
>> Hi Florent,
>>
>> The ugliness of my test case was simply my uncertainty about how timerate works. After Serg's clarification I realized that transform= can handle : inside a timerate block as long as the : command starts on its own line. My transform= is not a full Tcl parser -- it uses 5 or 6 regexps and doesn't count brace nesting levels -- so I accept that compromise. Here is the cleaner test Serg suggested:
>>
>> % proc= test {x y} {
>> timerate {
>> : list(x-10,x+20,y-20,y+20)
>> }
>> }
>> % test 5 20
>> 0.260845 µs/# 3833681 #/sec 999.997 net-ms
>>
>> % proc test2 {x y} {
>> timerate {
>> list [expr {$x-10}] [expr {$x+20}] [expr {$y-20}] [expr {$y+20}]
>> }
>> }
>> % test2 5 10
>> 0.253317 µs/# 3947624 #/sec 1000.000 net-ms
>>
>> Essentially identical -- and the disassembly confirms why: both produce exactly the same bytecode.
>>
>> As for why I used an infix expression compiler rather than extending expr -- two reasons. First, Colin had already written a beautiful pure Tcl Pratt parser that I could build on immediately. Second, at the time I had no understanding of how bytecode and the assembler worked, so using Colin's compiler as a front end to generate TAL was the obvious path. It turned out to be a fortunate choice since it required no core changes at all.
>>
>> Regarding your bytecode interface proposal -- I think you may be underestimating the scope of what tclAssembly.c actually does. The parser touch points you list are just the entry points. The 4400 lines handle label resolution, stack depth verification, LVT management, exception range tracking, operand encoding, and error reporting for 130+ opcodes. That infrastructure already exists and works -- which is exactly why I am arguing for a public interface to it rather than new parser syntax on top of it.
>>
>> Best regards,
>> Eric
>>
>>
>>
>>
>>
>> On Thu, Apr 23, 2026 at 9:53 PM Florent Merlet <flo...@gm...>
>> wrote:
>>
>>> 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
>>> _______________________________________________
>>> 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: Florent M. <flo...@gm...> - 2026-04-24 07:27:16
|
Ok.
Notice that my proposal doesn't need any new command named 'proc='.
I can just do :
proc test {x y} {
puts orig:[timerate {list [ .... ]}]
puts shorthand:[timerate {( ... )}]
}
to compare two bytecodes.
can you do this with your proposal ?
proc test {x y} {
puts orig:[timerate {list [ .... ]}]
puts colon:[timerate {: ... }]
}
If i want to compile a whole proc as expression, i can do :
proc p args {( ... )}
How will you get this effect with your proposal ?
proc p args {: { ... }}
proc= p args { ... }
The last one is 1 char shorther, but need a new command.
With my proposal, you can do :
eval {( .... )}
for {( .... )} {....} {( .... )} {( .... )}
If { } then {( .... )} else {( .... )}
Switch $a { case {( .... )} default {( .... )} }
Foreach i $L {( .... )}
Lmap j $K {( .... )}
... Etc
And get it bytecompiled with the expression parser where there is
parenthesis.
Can your proposal do this ?
Regards,
Florent
Le ven. 24 avr. 2026, 07:42, EricT <tw...@gm...> a écrit :
> Hi Florent,
>
> The ugliness of my test case was simply my uncertainty about how timerate works. After Serg's clarification I realized that transform= can handle : inside a timerate block as long as the : command starts on its own line. My transform= is not a full Tcl parser -- it uses 5 or 6 regexps and doesn't count brace nesting levels -- so I accept that compromise. Here is the cleaner test Serg suggested:
>
> % proc= test {x y} {
> timerate {
> : list(x-10,x+20,y-20,y+20)
> }
> }
> % test 5 20
> 0.260845 µs/# 3833681 #/sec 999.997 net-ms
>
> % proc test2 {x y} {
> timerate {
> list [expr {$x-10}] [expr {$x+20}] [expr {$y-20}] [expr {$y+20}]
> }
> }
> % test2 5 10
> 0.253317 µs/# 3947624 #/sec 1000.000 net-ms
>
> Essentially identical -- and the disassembly confirms why: both produce exactly the same bytecode.
>
> As for why I used an infix expression compiler rather than extending expr -- two reasons. First, Colin had already written a beautiful pure Tcl Pratt parser that I could build on immediately. Second, at the time I had no understanding of how bytecode and the assembler worked, so using Colin's compiler as a front end to generate TAL was the obvious path. It turned out to be a fortunate choice since it required no core changes at all.
>
> Regarding your bytecode interface proposal -- I think you may be underestimating the scope of what tclAssembly.c actually does. The parser touch points you list are just the entry points. The 4400 lines handle label resolution, stack depth verification, LVT management, exception range tracking, operand encoding, and error reporting for 130+ opcodes. That infrastructure already exists and works -- which is exactly why I am arguing for a public interface to it rather than new parser syntax on top of it.
>
> Best regards,
> Eric
>
>
>
>
>
> On Thu, Apr 23, 2026 at 9:53 PM Florent Merlet <flo...@gm...>
> wrote:
>
>> 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
>> _______________________________________________
>> Tcl-Core mailing list
>> Tcl...@li...
>> https://lists.sourceforge.net/lists/listinfo/tcl-core
>>
>
|
|
From: EricT <tw...@gm...> - 2026-04-24 05:42:34
|
Hi Florent,
The ugliness of my test case was simply my uncertainty about how
timerate works. After Serg's clarification I realized that transform=
can handle : inside a timerate block as long as the : command starts
on its own line. My transform= is not a full Tcl parser -- it uses 5
or 6 regexps and doesn't count brace nesting levels -- so I accept
that compromise. Here is the cleaner test Serg suggested:
% proc= test {x y} {
timerate {
: list(x-10,x+20,y-20,y+20)
}
}
% test 5 20
0.260845 µs/# 3833681 #/sec 999.997 net-ms
% proc test2 {x y} {
timerate {
list [expr {$x-10}] [expr {$x+20}] [expr {$y-20}] [expr {$y+20}]
}
}
% test2 5 10
0.253317 µs/# 3947624 #/sec 1000.000 net-ms
Essentially identical -- and the disassembly confirms why: both
produce exactly the same bytecode.
As for why I used an infix expression compiler rather than extending
expr -- two reasons. First, Colin had already written a beautiful pure
Tcl Pratt parser that I could build on immediately. Second, at the
time I had no understanding of how bytecode and the assembler worked,
so using Colin's compiler as a front end to generate TAL was the
obvious path. It turned out to be a fortunate choice since it required
no core changes at all.
Regarding your bytecode interface proposal -- I think you may be
underestimating the scope of what tclAssembly.c actually does. The
parser touch points you list are just the entry points. The 4400 lines
handle label resolution, stack depth verification, LVT management,
exception range tracking, operand encoding, and error reporting for
130+ opcodes. That infrastructure already exists and works -- which is
exactly why I am arguing for a public interface to it rather than new
parser syntax on top of it.
Best regards,
Eric
On Thu, Apr 23, 2026 at 9:53 PM Florent Merlet <flo...@gm...>
wrote:
> 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
> _______________________________________________
> Tcl-Core mailing list
> Tcl...@li...
> https://lists.sourceforge.net/lists/listinfo/tcl-core
>
|
|
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
|