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
(202) |
Dec
|
|
From: Christian W. <Chr...@t-...> - 2025-11-06 05:45:16
|
On 11/06/2025 12:18 AM, Jan Nijtmans wrote: > Op wo 5 nov 2025 om 21:06 schreef Paul Obermeier <pa...@po...>: >> 1 warning during Tk compilation: >> Tk/generic/ttk/ttkCache.c: In function 'InitCacheWindow': >> Tk/generic/ttk/ttkCache.c:256:64: warning: unused parameter 'tkwin' [-Wunused-parameter] >> static void InitCacheWindow(Ttk_ResourceCache cache, Tk_Window tkwin) > > There are two ways to solve this: > 1) change line 259 from > cache->tkwin = Tk_MainWindow(cache->interp); > to > cache->tkwin = tkwin; > this was how the line looked like originally. > > 2) Replace separate 'tkwin' arguments with 'cache->tkwin' in more places. > Experiment: > https://core.tcl-lang.org/tk/info/ed67b8e0980fd5af > > Does anyone (Christian???) have any advice here? Both ways are contradictory to the objective, which is to support multiple displays plus weird combinations of visuals and colormaps. So what about just using the much-loved TCL_UNUSED macro there? Or even strip off that parameter in InitCacheWindow()? Regards, Christian |
|
From: Jan N. <jan...@gm...> - 2025-11-05 23:18:28
|
Op wo 5 nov 2025 om 21:06 schreef Paul Obermeier <pa...@po...>:
> 1 warning during Tk compilation:
> Tk/generic/ttk/ttkCache.c: In function 'InitCacheWindow':
> Tk/generic/ttk/ttkCache.c:256:64: warning: unused parameter 'tkwin' [-Wunused-parameter]
> static void InitCacheWindow(Ttk_ResourceCache cache, Tk_Window tkwin)
There are two ways to solve this:
1) change line 259 from
cache->tkwin = Tk_MainWindow(cache->interp);
to
cache->tkwin = tkwin;
this was how the line looked like originally.
2) Replace separate 'tkwin' arguments with 'cache->tkwin' in more places.
Experiment:
https://core.tcl-lang.org/tk/info/ed67b8e0980fd5af
Does anyone (Christian???) have any advice here?
Regards,
Jan Nijtmans
|
|
From: EricT <tw...@gm...> - 2025-11-05 22:22:31
|
Hi Colin,
I've successfully modified your amazing code to handle arrays. In
doing so, I also found 2 other issues, one is with your Boolean check,
the other with your function name check, both because of [string is]
issues.
- Boolean check: `$token eq "false" || $token eq "true"` (was `[string
is boolean $token]` - treated 'f','n', 't', 'y', etc. variables as
boolean false, no, true, yes, ...)
- Function check: `[regexp {^[[:alpha:]]} $token]` (was `[string is
alpha $token]` - broke log10, atan2)
here's the code for arrays:
# Function call or array reference?
set nexttok [lindex $::tokens $::tokpos]
if {$nexttok eq "(" && [regexp {^[[:alpha:]]} $token]} {
set fun [namespace which tcl::mathfunc::$token]
if {$fun ne {}} {
# It's a function
incr ::tokpos
set opcodes "push $fun; "
append opcodes [parseFuncArgs]
return $opcodes
} else {
# Not a function, assume array reference
incr ::tokpos
set opcodes "push $token; "
# Parse the index expression - leaves VALUE on stack
append opcodes [parse 0]
# Expect closing paren
set closing [lindex $::tokens $::tokpos]
if {$closing ne ")"} {
error "Calc: expected ')' but found '$closing'"
}
# Stack now has: [arrayname, indexvalue]
incr ::tokpos
append opcodes "loadArrayStk; "
return $opcodes
}
}
In addition, there has indeed been some changes in the bytecode, land
and lor are no longer supported in 9.0 although they work in 8.6.
I had an AI generate some 117 test cases, which all pass on 8.6 and
111 on 9.x (the land/lor not being tested in 9.x).
Colin, with your permission, I can post the code as a new file, with
all the test cases, say on a repository at github.
I think a new TIP is worth considering; one that promotes assemble to
a supported form, with a compile and handle approach to avoid the time
parsing the ascii byte code text. I think that this would be great for
your = command, but also quite useful for others who might want to
create their own little languages.
By doing it this way, it remains pure tcl, and avoids all the problems
with different systems and hardware that a binary extension would
create. In the end, I believe your code can achieve performance parity
with expr. Not only does it remove half the [expr {...}] baggage, but
all the $'s too! So much easier on these old eyes.
Regards,
Eric
On Tue, Nov 4, 2025 at 1:06 PM EricT <tw...@gm...> wrote:
> Hi Colin,
>
> Hmmm, why can't you do bareword on $a(b) as a(b) you just need to do an
> uplevel to see if a is a variable, if not, it would have to be a function.
> True?
>
> % tcl::unsupported::disassemble script {set a [expr {$b($c)}] }
> snip
> Command 2: "expr {$b($c)}..."
> (2) push1 1 # "b"
> (4) push1 2 # "c"
> (6) loadStk
> (7) loadArrayStk
> (8) tryCvtToNumeric
> (9) storeStk
> (10) done
>
> This doesn't look too much different from what you are producing.
>
> I think what's really needed here is a TIP that would open up the bytecode
> a bit so you don't need to use an unsupported command. And then maybe even
> have a new command to take the string byte code you are now producing and
> return a handle to a cached version that was probably equivalent to the
> existing bytecode. Then your cache array would be
>
> set cache($exp) $handle
>
> Instead of it having to parse the text, it could be as fast as bytecode.
> You'd likely be just as fast as expr, and safe as well, since you can't
> pass a string command in where the bareword is required:
>
> % set x {[pwd]}
> [pwd]
> % = sqrt(x)
> exp= |sqrt(x)| code= |push ::tcl::mathfunc::sqrt; push x; loadStk;
> invokeStk 2; | ifexist: 0
> expected floating-point number but got "[pwd]"
>
> I think you really have something here, perhaps this is the best answer
> yet to slay the expr dragon!
>
> Regards,
>
> Eric
>
>
> On Tue, Nov 4, 2025 at 6:52 AM Colin Macleod via Tcl-Core <
> tcl...@li...> wrote:
>
>> Hi Eric,
>>
>> That's very neat!
>>
>> Yes, a pure Tcl version could go into TclLib. I still think it may be
>> worth trying a C implementation though. The work-around that's needed for
>> array references [= 2* $a(b)] would defeat the caching, so it would be good
>> to speed up the parsing if possible. Also I think your caching may be
>> equivalent to doing byte-compilation, in which case it may make sense to
>> use the framework which already exists for that.
>>
>> Colin.
>> On 04/11/2025 01:18, EricT wrote:
>>
>> that is:
>>
>> if {[info exist ::cache($exp)]} {
>> tailcall ::tcl::unsupported::assemble $::cache($exp)
>> }
>>
>> (hate gmail!)
>>
>>
>> On Mon, Nov 3, 2025 at 5:17 PM EricT <tw...@gm...> wrote:
>>
>>> and silly of me, it should be:
>>> if {[info exist ::cache($exp)]} {
>>> tailcall ::tcl::unsupported::assemble $::cache($exp)
>>> }
>>>
>>>
>>> On Mon, Nov 3, 2025 at 4:50 PM EricT <tw...@gm...> wrote:
>>>
>>>> With a debug line back in plus the tailcall:
>>>>
>>>> proc = args {
>>>> set exp [join $args]
>>>> if { [info exist ::cache($exp)] } {
>>>> return [tailcall ::tcl::unsupported::assemble $::cache($exp)]
>>>> }
>>>> set tokens [tokenise $exp]
>>>> deb1 "TOKENS = '$tokens'"
>>>> set code [compile $tokens]
>>>> deb1 "GENERATED CODE:\n$code\n"
>>>> puts "exp= |$exp| code= |$code| ifexist: [info exist ::cache($exp)]"
>>>> set ::cache($exp) $code
>>>> uplevel [list ::tcl::unsupported::assemble $code]
>>>> }
>>>>
>>>> % set a 5
>>>> 5
>>>> % set b 10
>>>> 10
>>>> % = a + b
>>>> exp= |a + b| code= |push a; loadStk; push b; loadStk; add; | ifexist: 0
>>>> 15
>>>> % = a + b
>>>> 15
>>>>
>>>> % time {= a + b} 1000
>>>> 1.73 microseconds per iteration
>>>>
>>>>
>>>> Faster still!
>>>>
>>>> I thought the uplevel was needed to be able to get the local variables,
>>>> seems not.
>>>>
>>>> % proc foo arg {set a 5; set b 10; set c [= a+b+arg]}
>>>> % foo 5
>>>> exp= |a+b+arg| code= |push a; loadStk; push b; loadStk; add; push arg;
>>>> loadStk; add; | ifexist: 0
>>>> 20
>>>> % foo 5
>>>> 20
>>>>
>>>> % proc foo arg {global xxx; set a 5; set b 10; set c [= a+b+arg+xxx]}
>>>>
>>>> % set xxx 100
>>>> 100
>>>> % foo 200
>>>> 315
>>>> % time {foo 200} 10000
>>>> 2.1775 microseconds per iteration
>>>>
>>>> % parray cache
>>>> cache(a + b) = push a; loadStk; push b; loadStk; add;
>>>> cache(a+b+arg) = push a; loadStk; push b; loadStk; add; push arg;
>>>> loadStk; add;
>>>> cache(a+b+arg+xxx) = push a; loadStk; push b; loadStk; add; push arg;
>>>> loadStk; add; push xxx; loadStk; add;
>>>>
>>>>
>>>> Very Impressive, great job Colin! Great catch Don!
>>>>
>>>> Eric
>>>>
>>>>
>>>>
>>>>
>>>> On Mon, Nov 3, 2025 at 4:22 PM Donald Porter via Tcl-Core <
>>>> tcl...@li...> wrote:
>>>>
>>>>> Check what effect replacing [uplevel] with [tailcall] has.
>>>>>
>>>>> On Nov 3, 2025, at 7:13 PM, EricT <tw...@gm...> wrote:
>>>>>
>>>>> Subject: Your bytecode expression evaluator - impressive results with
>>>>> caching!
>>>>>
>>>>> Hey Colin:
>>>>>
>>>>> I took a look at your bytecode-based expression evaluator and was
>>>>> intrigued by the approach. I made a small modification to add caching and
>>>>> the results are really impressive. Here's what I changed:
>>>>>
>>>>> proc = args {
>>>>> set exp [join $args]
>>>>> if {[info exist ::cache($exp)]} {
>>>>> return [uplevel [list ::tcl::unsupported::assemble
>>>>> $::cache($exp)]]
>>>>> }
>>>>> set tokens [tokenise $exp]
>>>>> deb1 "TOKENS = '$tokens'"
>>>>> set code [compile $tokens]
>>>>> deb1 "GENERATED CODE:\n$code\n"
>>>>> set ::cache($exp) $code
>>>>> uplevel [list ::tcl::unsupported::assemble $code]
>>>>> }
>>>>>
>>>>> The cache is just a simple array lookup - one line to store, one line
>>>>> to retrieve. But the performance impact is huge:
>>>>>
>>>>> Performance Tests
>>>>>
>>>>> Without caching
>>>>> % time {= 1 + 2} 1000
>>>>> 24.937 microseconds per iteration
>>>>>
>>>>> With caching
>>>>> % time {= 1 + 2} 1000
>>>>> 1.8 microseconds per iteration
>>>>>
>>>>> That's a 13x speedup! The tokenize and parse steps were eating about
>>>>> 92% of the execution time.
>>>>>
>>>>> The Real Magic: Bare Variables + Caching
>>>>>
>>>>> What really impressed me is how well your bare variable feature
>>>>> synergizes with caching:
>>>>>
>>>>> % set a 5
>>>>> 5
>>>>> % set b 6
>>>>> 6
>>>>> % = a + b
>>>>> 11
>>>>> % time {= a + b} 1000
>>>>> 2.079 microseconds per iteration
>>>>>
>>>>> Now change the variable values
>>>>> % set a 10
>>>>> 10
>>>>> % = a + b
>>>>> 16
>>>>> % time {= a + b} 1000
>>>>> 2.188 microseconds per iteration
>>>>>
>>>>> The cache entry stays valid even when the variable values change! Why?
>>>>> Because the bytecode stores variable names, not values:
>>>>>
>>>>> push a; loadStk; push b; loadStk; add;
>>>>>
>>>>> The loadStk instruction does runtime lookup, so:
>>>>> - Cache key is stable: "a + b"
>>>>> - Works for any values of a and b
>>>>> - One cache entry handles all value combinations
>>>>>
>>>>> Compare this to if we used $-substitution:
>>>>>
>>>>> = $a + $b # With a=5, b=6 becomes "5 + 6"
>>>>> = $a + $b # With a=10, b=6 becomes "10 + 6" - different cache key!
>>>>>
>>>>> Every value change would create a new cache entry or worse, a cache
>>>>> miss.
>>>>>
>>>>> Comparison to Other Approaches
>>>>>
>>>>> Tcl's expr: about 0.40 microseconds
>>>>> Direct C evaluator: about 0.53 microseconds
>>>>> Your cached approach: about 1.80 microseconds
>>>>> Your uncached approach: about 24.9 microseconds
>>>>>
>>>>> With caching, you're only 3-4x slower than a direct C evaluator.
>>>>>
>>>>>
>>>>> My Assessment
>>>>>
>>>>> Your design is excellent. The bare variable feature isn't just syntax
>>>>> sugar - it's essential for good cache performance. The synergy between:
>>>>>
>>>>> 1. Bare variables leading to stable cache keys
>>>>> 2. Runtime lookup keeping cache hot
>>>>> 3. Simple caching providing dramatic speedup
>>>>>
>>>>> makes this really elegant.
>>>>>
>>>>> My recommendation: Keep it in Tcl! The implementation is clean,
>>>>> performance is excellent (1.8 microseconds is plenty fast), and converting
>>>>> to C would add significant complexity for minimal gain (maybe getting to
>>>>> about 1.0 microseconds).
>>>>>
>>>>> The Tcl prototype with caching is actually the right solution here.
>>>>> Sometimes the prototype IS the product!
>>>>>
>>>>> Excellent work on this. The bytecode approach really shines with
>>>>> caching enabled.
>>>>>
>>>>> On Sun, Nov 2, 2025 at 10:14 AM Colin Macleod via Tcl-Core <
>>>>> tcl...@li...> wrote:
>>>>>
>>>>>> Hi again,
>>>>>>
>>>>>> I've now made a slightly more serious prototype, see
>>>>>> https://cmacleod.me.uk/tcl/expr_ng
>>>>>>
>>>>>> This is a modified version of the prototype I wrote for tip 676. It's
>>>>>> still in Tcl, but doesn't use `expr`. It tokenises and parses the input,
>>>>>> then generates TAL bytecode and uses ::tcl::unsupported::assemble to run
>>>>>> that. A few examples:
>>>>>>
>>>>>> (bin) 100 % set a [= 3.0/4]
>>>>>> 0.75
>>>>>> (bin) 101 % set b [= sin(a*10)]
>>>>>> 0.9379999767747389
>>>>>> (bin) 102 % set c [= (b-a)*100]
>>>>>> 18.79999767747389
>>>>>> (bin) 103 % namespace eval nn {set d [= 10**3]}
>>>>>> 1000
>>>>>> (bin) 104 % set e [= a?nn::d:b]
>>>>>> 1000
>>>>>> (bin) 105 % = {3 + [pwd]}
>>>>>> Calc: expected start of expression but found '[pwd]'
>>>>>> (bin) 106 % = {3 + $q}
>>>>>> Calc: expected start of expression but found '$q'
>>>>>> (bin) 107 % = sin (12)
>>>>>> -0.5365729180004349
>>>>>>
>>>>>> (bin) 108 % array set rr {one 1 two 2 three 3}
>>>>>> (bin) 110 % = a * rr(two)
>>>>>> Calc: expected operator but found '('
>>>>>> (bin) 111 % = a * $rr(two)
>>>>>> 1.5
>>>>>>
>>>>>> - You can use $ to get an array value substituted before the `=` code
>>>>>> sees the expression.
>>>>>>
>>>>>> (bin) 112 % string repeat ! [= nn::d / 15]
>>>>>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
>>>>>>
>>>>>> Colin.
>>>>>> On 02/11/2025 09:04, Donal Fellows wrote:
>>>>>>
>>>>>> Doing the job properly would definitely involve changing the
>>>>>> expression parser, with my suggested fix being to turn all bare words not
>>>>>> otherwise recognised as constants or in positions that look like function
>>>>>> calls (it's a parser with some lookahead) into simple variable reads (NB: C
>>>>>> resolves such ambiguities within itself differently, but that's one of the
>>>>>> nastiest parts of the language). We would need to retain $ support for
>>>>>> resolving ambiguity (e.g., array reads vs function calls; you can't safely
>>>>>> inspect the interpreter to resolve it at the time of compiling the
>>>>>> expression due to traces and unknown handlers) as well as compatibility,
>>>>>> but that's doable as it is a change only in cases that are currently errors.
>>>>>>
>>>>>> Adding assignment is quite a bit trickier, as that needs a new major
>>>>>> syntax class to describe the left side of the assignment. I suggest
>>>>>> omitting that from consideration at this stage.
>>>>>>
>>>>>> Donal.
>>>>>>
>>>>>> -------- Original message --------
>>>>>> From: Colin Macleod via Tcl-Core <tcl...@li...>
>>>>>> <tcl...@li...>
>>>>>> Date: 02/11/2025 08:13 (GMT+00:00)
>>>>>> To: Pietro Cerutti <ga...@ga...> <ga...@ga...>
>>>>>> Cc: tcl...@li..., av...@lo...
>>>>>> Subject: Re: [TCLCORE] Fwd: TIP 672 Implementation Complete - Ready
>>>>>> for Sponsorship
>>>>>>
>>>>>> Indeed, this toy implementation doesn't handle that:
>>>>>>
>>>>>> % = sin (12)
>>>>>> can't read "sin": no such variable
>>>>>>
>>>>>> I'm not sure that's serious, but it could be fixed in a C
>>>>>> implementation.
>>>>>>
>>>>>> _______________________________________________
>>>>>> 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
>>>>>
>>>>
>>
>> _______________________________________________
>> Tcl-Core mailing lis...@li...://lists.sourceforge.net/lists/listinfo/tcl-core
>>
>> _______________________________________________
>> Tcl-Core mailing list
>> Tcl...@li...
>> https://lists.sourceforge.net/lists/listinfo/tcl-core
>>
>
|
|
From: Paul O. <pa...@po...> - 2025-11-05 20:06:09
|
Here are the results of the TclTk 9.0.3 test suites using my BAWT build environments. No show-stoppers detected. 1 warning during Tk compilation: Tk/generic/ttk/ttkCache.c: In function 'InitCacheWindow': Tk/generic/ttk/ttkCache.c:256:64: warning: unused parameter 'tkwin' [-Wunused-parameter] static void InitCacheWindow(Ttk_ResourceCache cache, Tk_Window tkwin) Tcl 9.0.3: Operating system Arch. Compiler Errors ---------------------------------------------------- MacOS 15.7.1 M2 clang 17.0.0 0 Suse 15.6 x86_64 gcc 7.5.0 0 Raspberry Pi OS arm64 gcc 12.2.0 0 Debian (StarFive) RiscV gcc 12.2.0 1 Windows 11 x86 gcc 14.2.0 3 Windows 11 x86_64 gcc 14.2.0 3 Windows 11 x86_64 VS2022 3 Tk 9.0.3: Operating system Arch. Compiler Errors ---------------------------------------------------- MacOS 15.7.1 M2 clang 17.0.0 0 Suse 15.6 x86_64 gcc 7.5.0 59 Raspberry Pi OS arm64 gcc 12.2.0 42 Debian (StarFive) RiscV gcc 12.2.0 38 Windows 11 x86 gcc 14.2.0 0 Windows 11 x86_64 gcc 14.2.0 0 Windows 11 x86_64 VS2022 0 The usual 3 Windows failures: ==== fCmd-9.3 file rename: comprehensive: file to new name FAILED ==== fCmd-9.10 file rename: comprehensive: file to new name and dir FAILED ==== winFCmd-3.10 TclpDeleteFile: path is readonly FAILED The usual multiple Tk failures on Linux. The usual StarFive failure: ==== binary-40.3 ScanNumber: NaN FAILED Paul Am 05.11.2025 um 14:16 schrieb Jan Nijtmans: > Now available at > > https://sourceforge.net/projects/tcl/files/Tcl/9.0.3/ > > are RC0 candidate source code distribution pre-releases of Tcl/Tk 9.0.3 > > This is the first candidate release leading to the release of Tcl/Tk > 9.0.3. Testing of builds > and operations on multiple platforms is invited. Any critical problem > that should block > the release should be reported immediately. > > Only the full *-src.tar.gz files are there, the zip-files and the stripped-down > versions will follow. > > Preliminary release notes are available as well. Please report any > suggestions/improvements you may find. > > Thank you for your contributions and assistance. > Jan Nijtmans > > > _______________________________________________ > Tcl-Core mailing list > Tcl...@li... > https://lists.sourceforge.net/lists/listinfo/tcl-core |
|
From: Jan N. <jan...@gm...> - 2025-11-05 14:20:49
|
Done. Op wo 5 nov 2025 om 15:07 schreef Pietro Cerutti <ga...@ga...>: > > On Nov 05 2025, 13:16 +0000, Jan Nijtmans <jan...@gm...> wrote: > >Now available at > > > >https://sourceforge.net/projects/tcl/files/Tcl/9.0.3/ > > > >are RC0 candidate source code distribution pre-releases of Tcl/Tk 9.0.3 > > Typically, the source file would be named tcl9.0.3rc0-src.tar.gz while > in this case it's called tcl9.0.3-rc0-src.tar.gz, with an extra dash > between the version and rc0. > > If it's not too much work, can you please rename the files so downstream > doesn't have to adjust the tooling? > > Thanks! > > Pietro > > -- > Pietro Cerutti > I have pledged to give 10% of income to effective charities > and invite you to join me - https://givingwhatwecan.org |
|
From: Pietro C. <ga...@ga...> - 2025-11-05 14:07:33
|
On Nov 05 2025, 13:16 +0000, Jan Nijtmans <jan...@gm...> wrote: >Now available at > >https://sourceforge.net/projects/tcl/files/Tcl/9.0.3/ > >are RC0 candidate source code distribution pre-releases of Tcl/Tk 9.0.3 Typically, the source file would be named tcl9.0.3rc0-src.tar.gz while in this case it's called tcl9.0.3-rc0-src.tar.gz, with an extra dash between the version and rc0. If it's not too much work, can you please rename the files so downstream doesn't have to adjust the tooling? Thanks! Pietro -- Pietro Cerutti I have pledged to give 10% of income to effective charities and invite you to join me - https://givingwhatwecan.org |
|
From: Jan N. <jan...@gm...> - 2025-11-05 13:16:59
|
Now available at https://sourceforge.net/projects/tcl/files/Tcl/9.0.3/ are RC0 candidate source code distribution pre-releases of Tcl/Tk 9.0.3 This is the first candidate release leading to the release of Tcl/Tk 9.0.3. Testing of builds and operations on multiple platforms is invited. Any critical problem that should block the release should be reported immediately. Only the full *-src.tar.gz files are there, the zip-files and the stripped-down versions will follow. Preliminary release notes are available as well. Please report any suggestions/improvements you may find. Thank you for your contributions and assistance. Jan Nijtmans |
|
From: Kevin W. <kw...@co...> - 2025-11-05 11:56:39
|
Hi, Friendly reminder that voting on this TIP runs through this Friday. —Kevin > On Nov 1, 2025, at 8:36 PM, Kevin Walzer <kw...@co...> wrote: > > Hi all, > > I've had no additional feedback on TIP 733 in the past week, and I believe the tka11y branch is ready for merging, so I'd like to call for a TCT vote. > > Let's have votes in by [clock format 1762559940 -gmt 1]. > > My vote: TIP 733: YES > > --Kevin > > > > _______________________________________________ > Tcl-Core mailing list > Tcl...@li... > https://lists.sourceforge.net/lists/listinfo/tcl-core |
|
From: <apn...@ya...> - 2025-11-05 09:05:53
|
Now having looked at the unixInit-3.2 test, reason for failure is obvious. As the constraints on the test show, the test expects init.tcl in either ../../library or ../../../library and since TIP 732 explicitly disallows those for reasons detailed in the TIP, the test fails. Note the test would also fail in 9.0 were it not for the constraints which disable it if the build directory is not one or two levels under the source root.
The test itself is flawed / limited. It spawns a new process after unsetting the TCL_LIBRARY env variable. The purpose is ostensibly to ensure Tcl correctly finds the tcl_library location (and encodings) even without TCL_LIBRARY being set. However, while what it *should* be testing is whether tcl does this correctly as per the build configure setting, what it actually does is test if it does this correctly when built from within the source tree. Which is somewhat pointless in my opinion. (No platform has ../../library as its default configure setting). The constraints on the test to prevent failures under xcode builds, builds outside the source tree itself etc. are an indication of its limited utility.
(Aside - this mostly pertains to non-zipfs builds. zipfs builds pick up from the zipfs archive anyways.)
I therefore don't plan on making any 732 changes other than modifying the constraints to only run the test on zipfs builds (this is already partially present).
-----Original Message-----
From: Jan Nijtmans <jan...@gm...>
Well, I like this TIP, but there is a test failure on MacOS:
<https://github.com/tcltk/tcl/actions/runs/18965835171/job/54162420957>
==== unixInit-3.2 TclpSetInitialEncodings FAILED
|
|
From: Zaumseil R. <RZa...@kk...> - 2025-11-05 07:36:25
|
Thanks Csaba. Also for the improvements.
-----Ursprüngliche Nachricht-----
Von: Csaba Nemethi <csa...@t-...>
Gesendet: Dienstag, 4. November 2025 18:17
An: tcl...@li...
Betreff: [Ext] Re: [TCLCORE] Mousewheel for entry
Just in case, I have written a TIP related to this proposal. See
https://core.tcl-lang.org/tips/doc/trunk/tip/736.md
The implementation is in Tk branch "tip-736".
Any comments are welcome!
Best regards,
Csaba
Am 28.10.25 um 13:48 schrieb Harald Oehlmann:
> Am 28.10.2025 um 11:51 schrieb Zaumseil René via Tcl-Core:
>> Hello
>>
>> I would propose the following additional bindings.
>>
>> These bindings allow display of hidden parts of entries.
>>
>> bind Entry <MouseWheel> {tk::MouseWheel %W x %D -40.0 units}
>>
>> bind TEntry <MouseWheel> {tk::MouseWheel %W x %D -40.0 units}
>>
>> Can this be done without a tip?
> Yes, I think so. But a ticket would be great.
>
> Thanks for all,
> Harald
>
>
> _______________________________________________
> Tcl-Core mailing list
> Tcl...@li...
> https://lists.sourceforge.net/lists/listinfo/tcl-core
--
Csaba Nemethi https://www.nemethi.de mailto:csa...@t-...
_______________________________________________
Tcl-Core mailing list
Tcl...@li...
https://lists.sourceforge.net/lists/listinfo/tcl-core
|
|
From: EricT <tw...@gm...> - 2025-11-04 21:07:16
|
Hi Colin,
Hmmm, why can't you do bareword on $a(b) as a(b) you just need to do an
uplevel to see if a is a variable, if not, it would have to be a function.
True?
% tcl::unsupported::disassemble script {set a [expr {$b($c)}] }
snip
Command 2: "expr {$b($c)}..."
(2) push1 1 # "b"
(4) push1 2 # "c"
(6) loadStk
(7) loadArrayStk
(8) tryCvtToNumeric
(9) storeStk
(10) done
This doesn't look too much different from what you are producing.
I think what's really needed here is a TIP that would open up the bytecode
a bit so you don't need to use an unsupported command. And then maybe even
have a new command to take the string byte code you are now producing and
return a handle to a cached version that was probably equivalent to the
existing bytecode. Then your cache array would be
set cache($exp) $handle
Instead of it having to parse the text, it could be as fast as bytecode.
You'd likely be just as fast as expr, and safe as well, since you can't
pass a string command in where the bareword is required:
% set x {[pwd]}
[pwd]
% = sqrt(x)
exp= |sqrt(x)| code= |push ::tcl::mathfunc::sqrt; push x; loadStk;
invokeStk 2; | ifexist: 0
expected floating-point number but got "[pwd]"
I think you really have something here, perhaps this is the best answer yet
to slay the expr dragon!
Regards,
Eric
On Tue, Nov 4, 2025 at 6:52 AM Colin Macleod via Tcl-Core <
tcl...@li...> wrote:
> Hi Eric,
>
> That's very neat!
>
> Yes, a pure Tcl version could go into TclLib. I still think it may be
> worth trying a C implementation though. The work-around that's needed for
> array references [= 2* $a(b)] would defeat the caching, so it would be good
> to speed up the parsing if possible. Also I think your caching may be
> equivalent to doing byte-compilation, in which case it may make sense to
> use the framework which already exists for that.
>
> Colin.
> On 04/11/2025 01:18, EricT wrote:
>
> that is:
>
> if {[info exist ::cache($exp)]} {
> tailcall ::tcl::unsupported::assemble $::cache($exp)
> }
>
> (hate gmail!)
>
>
> On Mon, Nov 3, 2025 at 5:17 PM EricT <tw...@gm...> wrote:
>
>> and silly of me, it should be:
>> if {[info exist ::cache($exp)]} {
>> tailcall ::tcl::unsupported::assemble $::cache($exp)
>> }
>>
>>
>> On Mon, Nov 3, 2025 at 4:50 PM EricT <tw...@gm...> wrote:
>>
>>> With a debug line back in plus the tailcall:
>>>
>>> proc = args {
>>> set exp [join $args]
>>> if { [info exist ::cache($exp)] } {
>>> return [tailcall ::tcl::unsupported::assemble $::cache($exp)]
>>> }
>>> set tokens [tokenise $exp]
>>> deb1 "TOKENS = '$tokens'"
>>> set code [compile $tokens]
>>> deb1 "GENERATED CODE:\n$code\n"
>>> puts "exp= |$exp| code= |$code| ifexist: [info exist ::cache($exp)]"
>>> set ::cache($exp) $code
>>> uplevel [list ::tcl::unsupported::assemble $code]
>>> }
>>>
>>> % set a 5
>>> 5
>>> % set b 10
>>> 10
>>> % = a + b
>>> exp= |a + b| code= |push a; loadStk; push b; loadStk; add; | ifexist: 0
>>> 15
>>> % = a + b
>>> 15
>>>
>>> % time {= a + b} 1000
>>> 1.73 microseconds per iteration
>>>
>>>
>>> Faster still!
>>>
>>> I thought the uplevel was needed to be able to get the local variables,
>>> seems not.
>>>
>>> % proc foo arg {set a 5; set b 10; set c [= a+b+arg]}
>>> % foo 5
>>> exp= |a+b+arg| code= |push a; loadStk; push b; loadStk; add; push arg;
>>> loadStk; add; | ifexist: 0
>>> 20
>>> % foo 5
>>> 20
>>>
>>> % proc foo arg {global xxx; set a 5; set b 10; set c [= a+b+arg+xxx]}
>>>
>>> % set xxx 100
>>> 100
>>> % foo 200
>>> 315
>>> % time {foo 200} 10000
>>> 2.1775 microseconds per iteration
>>>
>>> % parray cache
>>> cache(a + b) = push a; loadStk; push b; loadStk; add;
>>> cache(a+b+arg) = push a; loadStk; push b; loadStk; add; push arg;
>>> loadStk; add;
>>> cache(a+b+arg+xxx) = push a; loadStk; push b; loadStk; add; push arg;
>>> loadStk; add; push xxx; loadStk; add;
>>>
>>>
>>> Very Impressive, great job Colin! Great catch Don!
>>>
>>> Eric
>>>
>>>
>>>
>>>
>>> On Mon, Nov 3, 2025 at 4:22 PM Donald Porter via Tcl-Core <
>>> tcl...@li...> wrote:
>>>
>>>> Check what effect replacing [uplevel] with [tailcall] has.
>>>>
>>>> On Nov 3, 2025, at 7:13 PM, EricT <tw...@gm...> wrote:
>>>>
>>>> Subject: Your bytecode expression evaluator - impressive results with
>>>> caching!
>>>>
>>>> Hey Colin:
>>>>
>>>> I took a look at your bytecode-based expression evaluator and was
>>>> intrigued by the approach. I made a small modification to add caching and
>>>> the results are really impressive. Here's what I changed:
>>>>
>>>> proc = args {
>>>> set exp [join $args]
>>>> if {[info exist ::cache($exp)]} {
>>>> return [uplevel [list ::tcl::unsupported::assemble
>>>> $::cache($exp)]]
>>>> }
>>>> set tokens [tokenise $exp]
>>>> deb1 "TOKENS = '$tokens'"
>>>> set code [compile $tokens]
>>>> deb1 "GENERATED CODE:\n$code\n"
>>>> set ::cache($exp) $code
>>>> uplevel [list ::tcl::unsupported::assemble $code]
>>>> }
>>>>
>>>> The cache is just a simple array lookup - one line to store, one line
>>>> to retrieve. But the performance impact is huge:
>>>>
>>>> Performance Tests
>>>>
>>>> Without caching
>>>> % time {= 1 + 2} 1000
>>>> 24.937 microseconds per iteration
>>>>
>>>> With caching
>>>> % time {= 1 + 2} 1000
>>>> 1.8 microseconds per iteration
>>>>
>>>> That's a 13x speedup! The tokenize and parse steps were eating about
>>>> 92% of the execution time.
>>>>
>>>> The Real Magic: Bare Variables + Caching
>>>>
>>>> What really impressed me is how well your bare variable feature
>>>> synergizes with caching:
>>>>
>>>> % set a 5
>>>> 5
>>>> % set b 6
>>>> 6
>>>> % = a + b
>>>> 11
>>>> % time {= a + b} 1000
>>>> 2.079 microseconds per iteration
>>>>
>>>> Now change the variable values
>>>> % set a 10
>>>> 10
>>>> % = a + b
>>>> 16
>>>> % time {= a + b} 1000
>>>> 2.188 microseconds per iteration
>>>>
>>>> The cache entry stays valid even when the variable values change! Why?
>>>> Because the bytecode stores variable names, not values:
>>>>
>>>> push a; loadStk; push b; loadStk; add;
>>>>
>>>> The loadStk instruction does runtime lookup, so:
>>>> - Cache key is stable: "a + b"
>>>> - Works for any values of a and b
>>>> - One cache entry handles all value combinations
>>>>
>>>> Compare this to if we used $-substitution:
>>>>
>>>> = $a + $b # With a=5, b=6 becomes "5 + 6"
>>>> = $a + $b # With a=10, b=6 becomes "10 + 6" - different cache key!
>>>>
>>>> Every value change would create a new cache entry or worse, a cache
>>>> miss.
>>>>
>>>> Comparison to Other Approaches
>>>>
>>>> Tcl's expr: about 0.40 microseconds
>>>> Direct C evaluator: about 0.53 microseconds
>>>> Your cached approach: about 1.80 microseconds
>>>> Your uncached approach: about 24.9 microseconds
>>>>
>>>> With caching, you're only 3-4x slower than a direct C evaluator.
>>>>
>>>>
>>>> My Assessment
>>>>
>>>> Your design is excellent. The bare variable feature isn't just syntax
>>>> sugar - it's essential for good cache performance. The synergy between:
>>>>
>>>> 1. Bare variables leading to stable cache keys
>>>> 2. Runtime lookup keeping cache hot
>>>> 3. Simple caching providing dramatic speedup
>>>>
>>>> makes this really elegant.
>>>>
>>>> My recommendation: Keep it in Tcl! The implementation is clean,
>>>> performance is excellent (1.8 microseconds is plenty fast), and converting
>>>> to C would add significant complexity for minimal gain (maybe getting to
>>>> about 1.0 microseconds).
>>>>
>>>> The Tcl prototype with caching is actually the right solution here.
>>>> Sometimes the prototype IS the product!
>>>>
>>>> Excellent work on this. The bytecode approach really shines with
>>>> caching enabled.
>>>>
>>>> On Sun, Nov 2, 2025 at 10:14 AM Colin Macleod via Tcl-Core <
>>>> tcl...@li...> wrote:
>>>>
>>>>> Hi again,
>>>>>
>>>>> I've now made a slightly more serious prototype, see
>>>>> https://cmacleod.me.uk/tcl/expr_ng
>>>>>
>>>>> This is a modified version of the prototype I wrote for tip 676. It's
>>>>> still in Tcl, but doesn't use `expr`. It tokenises and parses the input,
>>>>> then generates TAL bytecode and uses ::tcl::unsupported::assemble to run
>>>>> that. A few examples:
>>>>>
>>>>> (bin) 100 % set a [= 3.0/4]
>>>>> 0.75
>>>>> (bin) 101 % set b [= sin(a*10)]
>>>>> 0.9379999767747389
>>>>> (bin) 102 % set c [= (b-a)*100]
>>>>> 18.79999767747389
>>>>> (bin) 103 % namespace eval nn {set d [= 10**3]}
>>>>> 1000
>>>>> (bin) 104 % set e [= a?nn::d:b]
>>>>> 1000
>>>>> (bin) 105 % = {3 + [pwd]}
>>>>> Calc: expected start of expression but found '[pwd]'
>>>>> (bin) 106 % = {3 + $q}
>>>>> Calc: expected start of expression but found '$q'
>>>>> (bin) 107 % = sin (12)
>>>>> -0.5365729180004349
>>>>>
>>>>> (bin) 108 % array set rr {one 1 two 2 three 3}
>>>>> (bin) 110 % = a * rr(two)
>>>>> Calc: expected operator but found '('
>>>>> (bin) 111 % = a * $rr(two)
>>>>> 1.5
>>>>>
>>>>> - You can use $ to get an array value substituted before the `=` code
>>>>> sees the expression.
>>>>>
>>>>> (bin) 112 % string repeat ! [= nn::d / 15]
>>>>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
>>>>>
>>>>> Colin.
>>>>> On 02/11/2025 09:04, Donal Fellows wrote:
>>>>>
>>>>> Doing the job properly would definitely involve changing the
>>>>> expression parser, with my suggested fix being to turn all bare words not
>>>>> otherwise recognised as constants or in positions that look like function
>>>>> calls (it's a parser with some lookahead) into simple variable reads (NB: C
>>>>> resolves such ambiguities within itself differently, but that's one of the
>>>>> nastiest parts of the language). We would need to retain $ support for
>>>>> resolving ambiguity (e.g., array reads vs function calls; you can't safely
>>>>> inspect the interpreter to resolve it at the time of compiling the
>>>>> expression due to traces and unknown handlers) as well as compatibility,
>>>>> but that's doable as it is a change only in cases that are currently errors.
>>>>>
>>>>> Adding assignment is quite a bit trickier, as that needs a new major
>>>>> syntax class to describe the left side of the assignment. I suggest
>>>>> omitting that from consideration at this stage.
>>>>>
>>>>> Donal.
>>>>>
>>>>> -------- Original message --------
>>>>> From: Colin Macleod via Tcl-Core <tcl...@li...>
>>>>> <tcl...@li...>
>>>>> Date: 02/11/2025 08:13 (GMT+00:00)
>>>>> To: Pietro Cerutti <ga...@ga...> <ga...@ga...>
>>>>> Cc: tcl...@li..., av...@lo...
>>>>> Subject: Re: [TCLCORE] Fwd: TIP 672 Implementation Complete - Ready
>>>>> for Sponsorship
>>>>>
>>>>> Indeed, this toy implementation doesn't handle that:
>>>>>
>>>>> % = sin (12)
>>>>> can't read "sin": no such variable
>>>>>
>>>>> I'm not sure that's serious, but it could be fixed in a C
>>>>> implementation.
>>>>>
>>>>> _______________________________________________
>>>>> 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
>>>>
>>>
>
> _______________________________________________
> Tcl-Core mailing lis...@li...://lists.sourceforge.net/lists/listinfo/tcl-core
>
> _______________________________________________
> Tcl-Core mailing list
> Tcl...@li...
> https://lists.sourceforge.net/lists/listinfo/tcl-core
>
|
|
From: Csaba N. <csa...@t-...> - 2025-11-04 17:17:37
|
Just in case, I have written a TIP related to this proposal. See
https://core.tcl-lang.org/tips/doc/trunk/tip/736.md
The implementation is in Tk branch "tip-736".
Any comments are welcome!
Best regards,
Csaba
Am 28.10.25 um 13:48 schrieb Harald Oehlmann:
> Am 28.10.2025 um 11:51 schrieb Zaumseil René via Tcl-Core:
>> Hello
>>
>> I would propose the following additional bindings.
>>
>> These bindings allow display of hidden parts of entries.
>>
>> bind Entry <MouseWheel> {tk::MouseWheel %W x %D -40.0 units}
>>
>> bind TEntry <MouseWheel> {tk::MouseWheel %W x %D -40.0 units}
>>
>> Can this be done without a tip?
> Yes, I think so. But a ticket would be great.
>
> Thanks for all,
> Harald
>
>
> _______________________________________________
> Tcl-Core mailing list
> Tcl...@li...
> https://lists.sourceforge.net/lists/listinfo/tcl-core
--
Csaba Nemethi https://www.nemethi.de mailto:csa...@t-...
|
|
From: Kevin K. <kev...@gm...> - 2025-11-04 16:11:55
|
On Tue, Nov 4, 2025, 09:57 Colin Macleod via Tcl-Core < tcl...@li...> wrote: > Also relying on an "unsupported" facility is fine for a prototype but > risky for production code. > If there is a significant gain to be had here, all it would take is a TIP to provide limited support for the assembler. The 'unsupported' is there because we don't guarantee that the bytecode language is stable - we're free to change it for performance reasons, or indeed for any other good reason. Anything adopted to the Core is free to use whatever internal APIs the maintainers choose. > |
|
From: Colin M. <col...@ya...> - 2025-11-04 14:57:11
|
Also relying on an "unsupported" facility is fine for a prototype but
risky for production code.
On 04/11/2025 14:51, Colin Macleod via Tcl-Core wrote:
>
> Hi Eric,
>
> That's very neat!
>
> Yes, a pure Tcl version could go into TclLib. I still think it may be
> worth trying a C implementation though. The work-around that's needed
> for array references [= 2* $a(b)] would defeat the caching, so it
> would be good to speed up the parsing if possible. Also I think your
> caching may be equivalent to doing byte-compilation, in which case it
> may make sense to use the framework which already exists for that.
>
> Colin.
>
> On 04/11/2025 01:18, EricT wrote:
>> that is:
>>
>> if {[info exist ::cache($exp)]} {
>> tailcall ::tcl::unsupported::assemble $::cache($exp)
>> }
>>
>> (hate gmail!)
>>
>>
>> On Mon, Nov 3, 2025 at 5:17 PM EricT <tw...@gm...> wrote:
>>
>> and silly of me, it should be:
>> if {[info exist ::cache($exp)]} {
>> tailcall ::tcl::unsupported::assemble $::cache($exp)
>> }
>>
>>
>> On Mon, Nov 3, 2025 at 4:50 PM EricT <tw...@gm...> wrote:
>>
>> With a debug line back in plus the tailcall:
>>
>> proc = args {
>> set exp [join $args]
>> if { [info exist ::cache($exp)] } {
>> return [tailcall ::tcl::unsupported::assemble
>> $::cache($exp)]
>> }
>> set tokens [tokenise $exp]
>> deb1 "TOKENS = '$tokens'"
>> set code [compile $tokens]
>> deb1 "GENERATED CODE:\n$code\n"
>> puts "exp= |$exp| code= |$code| ifexist: [info exist
>> ::cache($exp)]"
>> set ::cache($exp) $code
>> uplevel [list ::tcl::unsupported::assemble $code]
>> }
>>
>> % set a 5
>> 5
>> % set b 10
>> 10
>> % = a + b
>> exp= |a + b| code= |push a; loadStk; push b; loadStk; add; |
>> ifexist: 0
>> 15
>> % = a + b
>> 15
>>
>> % time {= a + b} 1000
>> 1.73 microseconds per iteration
>>
>>
>> Faster still!
>>
>> I thought the uplevel was needed to be able to get the local
>> variables, seems not.
>>
>> % proc foo arg {set a 5; set b 10; set c [= a+b+arg]}
>> % foo 5
>> exp= |a+b+arg| code= |push a; loadStk; push b; loadStk; add;
>> push arg; loadStk; add; | ifexist: 0
>> 20
>> % foo 5
>> 20
>>
>> % proc foo arg {global xxx; set a 5; set b 10; set c [=
>> a+b+arg+xxx]}
>>
>> % set xxx 100
>> 100
>> % foo 200
>> 315
>> % time {foo 200} 10000
>> 2.1775 microseconds per iteration
>>
>> % parray cache
>> cache(a + b) = push a; loadStk; push b; loadStk; add;
>> cache(a+b+arg) = push a; loadStk; push b; loadStk; add;
>> push arg; loadStk; add;
>> cache(a+b+arg+xxx) = push a; loadStk; push b; loadStk; add;
>> push arg; loadStk; add; push xxx; loadStk; add;
>>
>>
>> Very Impressive, great job Colin! Great catch Don!
>>
>> Eric
>>
>>
>>
>>
>> On Mon, Nov 3, 2025 at 4:22 PM Donald Porter via Tcl-Core
>> <tcl...@li...> wrote:
>>
>> Check what effect replacing [uplevel] with [tailcall] has.
>>
>>> On Nov 3, 2025, at 7:13 PM, EricT <tw...@gm...> wrote:
>>>
>>> Subject: Your bytecode expression evaluator - impressive
>>> results with caching!
>>>
>>> Hey Colin:
>>>
>>> I took a look at your bytecode-based expression
>>> evaluator and was intrigued by the approach. I made a
>>> small modification to add caching and the results are
>>> really impressive. Here's what I changed:
>>>
>>> proc = args {
>>> set exp [join $args]
>>> if {[info exist ::cache($exp)]} {
>>> return [uplevel [list
>>> ::tcl::unsupported::assemble $::cache($exp)]]
>>> }
>>> set tokens [tokenise $exp]
>>> deb1 "TOKENS = '$tokens'"
>>> set code [compile $tokens]
>>> deb1 "GENERATED CODE:\n$code\n"
>>> set ::cache($exp) $code
>>> uplevel [list ::tcl::unsupported::assemble $code]
>>> }
>>>
>>> The cache is just a simple array lookup - one line to
>>> store, one line to retrieve. But the performance impact
>>> is huge:
>>>
>>> Performance Tests
>>>
>>> Without caching
>>> % time {= 1 + 2} 1000
>>> 24.937 microseconds per iteration
>>>
>>> With caching
>>> % time {= 1 + 2} 1000
>>> 1.8 microseconds per iteration
>>>
>>> That's a 13x speedup! The tokenize and parse steps were
>>> eating about 92% of the execution time.
>>>
>>> The Real Magic: Bare Variables + Caching
>>>
>>> What really impressed me is how well your bare variable
>>> feature synergizes with caching:
>>>
>>> % set a 5
>>> 5
>>> % set b 6
>>> 6
>>> % = a + b
>>> 11
>>> % time {= a + b} 1000
>>> 2.079 microseconds per iteration
>>>
>>> Now change the variable values
>>> % set a 10
>>> 10
>>> % = a + b
>>> 16
>>> % time {= a + b} 1000
>>> 2.188 microseconds per iteration
>>>
>>> The cache entry stays valid even when the variable
>>> values change! Why? Because the bytecode stores variable
>>> names, not values:
>>>
>>> push a; loadStk; push b; loadStk; add;
>>>
>>> The loadStk instruction does runtime lookup, so:
>>> - Cache key is stable: "a + b"
>>> - Works for any values of a and b
>>> - One cache entry handles all value combinations
>>>
>>> Compare this to if we used $-substitution:
>>>
>>> = $a + $b # With a=5, b=6 becomes "5 + 6"
>>> = $a + $b # With a=10, b=6 becomes "10 + 6" -
>>> different cache key!
>>>
>>> Every value change would create a new cache entry or
>>> worse, a cache miss.
>>>
>>> Comparison to Other Approaches
>>>
>>> Tcl's expr: about 0.40 microseconds
>>> Direct C evaluator: about 0.53 microseconds
>>> Your cached approach: about 1.80 microseconds
>>> Your uncached approach: about 24.9 microseconds
>>>
>>> With caching, you're only 3-4x slower than a direct C
>>> evaluator.
>>>
>>>
>>> My Assessment
>>>
>>> Your design is excellent. The bare variable feature
>>> isn't just syntax sugar - it's essential for good cache
>>> performance. The synergy between:
>>>
>>> 1. Bare variables leading to stable cache keys
>>> 2. Runtime lookup keeping cache hot
>>> 3. Simple caching providing dramatic speedup
>>>
>>> makes this really elegant.
>>>
>>> My recommendation: Keep it in Tcl! The implementation is
>>> clean, performance is excellent (1.8 microseconds is
>>> plenty fast), and converting to C would add significant
>>> complexity for minimal gain (maybe getting to about 1.0
>>> microseconds).
>>>
>>> The Tcl prototype with caching is actually the right
>>> solution here. Sometimes the prototype IS the product!
>>>
>>> Excellent work on this. The bytecode approach really
>>> shines with caching enabled.
>>>
>>> On Sun, Nov 2, 2025 at 10:14 AM Colin Macleod via
>>> Tcl-Core <tcl...@li...> wrote:
>>>
>>> Hi again,
>>>
>>> I've now made a slightly more serious prototype, see
>>> https://cmacleod.me.uk/tcl/expr_ng
>>>
>>> This is a modified version of the prototype I wrote
>>> for tip 676. It's still in Tcl, but doesn't use
>>> `expr`. It tokenises and parses the input, then
>>> generates TAL bytecode and uses
>>> ::tcl::unsupported::assemble to run that. A few
>>> examples:
>>>
>>> (bin) 100 % set a [= 3.0/4]
>>> 0.75
>>> (bin) 101 % set b [= sin(a*10)]
>>> 0.9379999767747389
>>> (bin) 102 % set c [= (b-a)*100]
>>> 18.79999767747389
>>> (bin) 103 % namespace eval nn {set d [= 10**3]}
>>> 1000
>>> (bin) 104 % set e [= a?nn::d:b]
>>> 1000
>>> (bin) 105 % = {3 + [pwd]}
>>> Calc: expected start of expression but found '[pwd]'
>>> (bin) 106 % = {3 + $q}
>>> Calc: expected start of expression but found '$q'
>>> (bin) 107 % = sin (12)
>>> -0.5365729180004349
>>>
>>> (bin) 108 % array set rr {one 1 two 2 three 3}
>>> (bin) 110 % = a * rr(two)
>>> Calc: expected operator but found '('
>>> (bin) 111 % = a * $rr(two)
>>> 1.5
>>>
>>> - You can use $ to get an array value substituted
>>> before the `=` code sees the expression.
>>>
>>> (bin) 112 % string repeat ! [= nn::d / 15]
>>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
>>>
>>> Colin.
>>>
>>> On 02/11/2025 09:04, Donal Fellows wrote:
>>>> Doing the job properly would definitely involve
>>>> changing the expression parser, with my suggested
>>>> fix being to turn all bare words not otherwise
>>>> recognised as constants or in positions that look
>>>> like function calls (it's a parser with some
>>>> lookahead) into simple variable reads (NB: C
>>>> resolves such ambiguities within itself
>>>> differently, but that's one of the nastiest parts
>>>> of the language). We would need to retain $ support
>>>> for resolving ambiguity (e.g., array reads vs
>>>> function calls; you can't safely inspect the
>>>> interpreter to resolve it at the time of compiling
>>>> the expression due to traces and unknown handlers)
>>>> as well as compatibility, but that's doable as it
>>>> is a change only in cases that are currently errors.
>>>>
>>>> Adding assignment is quite a bit trickier, as that
>>>> needs a new major syntax class to describe the left
>>>> side of the assignment. I suggest omitting that
>>>> from consideration at this stage.
>>>>
>>>> Donal.
>>>>
>>>> -------- Original message --------
>>>> From: Colin Macleod via Tcl-Core
>>>> <tcl...@li...>
>>>> <mailto:tcl...@li...>
>>>> Date: 02/11/2025 08:13 (GMT+00:00)
>>>> To: Pietro Cerutti <ga...@ga...>
>>>> <mailto:ga...@ga...>
>>>> Cc: tcl...@li..., av...@lo...
>>>> Subject: Re: [TCLCORE] Fwd: TIP 672 Implementation
>>>> Complete - Ready for Sponsorship
>>>>
>>>> Indeed, this toy implementation doesn't handle that:
>>>>
>>>> % = sin (12)
>>>> can't read "sin": no such variable
>>>>
>>>> I'm not sure that's serious, but it could be fixed
>>>> in a C implementation.
>>>>
>>> _______________________________________________
>>> 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
>>
>>
>>
>> _______________________________________________
>> 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: Colin M. <col...@ya...> - 2025-11-04 14:52:03
|
Hi Eric,
That's very neat!
Yes, a pure Tcl version could go into TclLib. I still think it may be
worth trying a C implementation though. The work-around that's needed
for array references [= 2* $a(b)] would defeat the caching, so it would
be good to speed up the parsing if possible. Also I think your caching
may be equivalent to doing byte-compilation, in which case it may make
sense to use the framework which already exists for that.
Colin.
On 04/11/2025 01:18, EricT wrote:
> that is:
>
> if {[info exist ::cache($exp)]} {
> tailcall ::tcl::unsupported::assemble $::cache($exp)
> }
>
> (hate gmail!)
>
>
> On Mon, Nov 3, 2025 at 5:17 PM EricT <tw...@gm...> wrote:
>
> and silly of me, it should be:
> if {[info exist ::cache($exp)]} {
> tailcall ::tcl::unsupported::assemble $::cache($exp)
> }
>
>
> On Mon, Nov 3, 2025 at 4:50 PM EricT <tw...@gm...> wrote:
>
> With a debug line back in plus the tailcall:
>
> proc = args {
> set exp [join $args]
> if { [info exist ::cache($exp)] } {
> return [tailcall ::tcl::unsupported::assemble
> $::cache($exp)]
> }
> set tokens [tokenise $exp]
> deb1 "TOKENS = '$tokens'"
> set code [compile $tokens]
> deb1 "GENERATED CODE:\n$code\n"
> puts "exp= |$exp| code= |$code| ifexist: [info exist
> ::cache($exp)]"
> set ::cache($exp) $code
> uplevel [list ::tcl::unsupported::assemble $code]
> }
>
> % set a 5
> 5
> % set b 10
> 10
> % = a + b
> exp= |a + b| code= |push a; loadStk; push b; loadStk; add; |
> ifexist: 0
> 15
> % = a + b
> 15
>
> % time {= a + b} 1000
> 1.73 microseconds per iteration
>
>
> Faster still!
>
> I thought the uplevel was needed to be able to get the local
> variables, seems not.
>
> % proc foo arg {set a 5; set b 10; set c [= a+b+arg]}
> % foo 5
> exp= |a+b+arg| code= |push a; loadStk; push b; loadStk; add;
> push arg; loadStk; add; | ifexist: 0
> 20
> % foo 5
> 20
>
> % proc foo arg {global xxx; set a 5; set b 10; set c [=
> a+b+arg+xxx]}
>
> % set xxx 100
> 100
> % foo 200
> 315
> % time {foo 200} 10000
> 2.1775 microseconds per iteration
>
> % parray cache
> cache(a + b) = push a; loadStk; push b; loadStk; add;
> cache(a+b+arg) = push a; loadStk; push b; loadStk; add;
> push arg; loadStk; add;
> cache(a+b+arg+xxx) = push a; loadStk; push b; loadStk; add;
> push arg; loadStk; add; push xxx; loadStk; add;
>
>
> Very Impressive, great job Colin! Great catch Don!
>
> Eric
>
>
>
>
> On Mon, Nov 3, 2025 at 4:22 PM Donald Porter via Tcl-Core
> <tcl...@li...> wrote:
>
> Check what effect replacing [uplevel] with [tailcall] has.
>
>> On Nov 3, 2025, at 7:13 PM, EricT <tw...@gm...> wrote:
>>
>> Subject: Your bytecode expression evaluator - impressive
>> results with caching!
>>
>> Hey Colin:
>>
>> I took a look at your bytecode-based expression evaluator
>> and was intrigued by the approach. I made a small
>> modification to add caching and the results are really
>> impressive. Here's what I changed:
>>
>> proc = args {
>> set exp [join $args]
>> if {[info exist ::cache($exp)]} {
>> return [uplevel [list
>> ::tcl::unsupported::assemble $::cache($exp)]]
>> }
>> set tokens [tokenise $exp]
>> deb1 "TOKENS = '$tokens'"
>> set code [compile $tokens]
>> deb1 "GENERATED CODE:\n$code\n"
>> set ::cache($exp) $code
>> uplevel [list ::tcl::unsupported::assemble $code]
>> }
>>
>> The cache is just a simple array lookup - one line to
>> store, one line to retrieve. But the performance impact
>> is huge:
>>
>> Performance Tests
>>
>> Without caching
>> % time {= 1 + 2} 1000
>> 24.937 microseconds per iteration
>>
>> With caching
>> % time {= 1 + 2} 1000
>> 1.8 microseconds per iteration
>>
>> That's a 13x speedup! The tokenize and parse steps were
>> eating about 92% of the execution time.
>>
>> The Real Magic: Bare Variables + Caching
>>
>> What really impressed me is how well your bare variable
>> feature synergizes with caching:
>>
>> % set a 5
>> 5
>> % set b 6
>> 6
>> % = a + b
>> 11
>> % time {= a + b} 1000
>> 2.079 microseconds per iteration
>>
>> Now change the variable values
>> % set a 10
>> 10
>> % = a + b
>> 16
>> % time {= a + b} 1000
>> 2.188 microseconds per iteration
>>
>> The cache entry stays valid even when the variable values
>> change! Why? Because the bytecode stores variable names,
>> not values:
>>
>> push a; loadStk; push b; loadStk; add;
>>
>> The loadStk instruction does runtime lookup, so:
>> - Cache key is stable: "a + b"
>> - Works for any values of a and b
>> - One cache entry handles all value combinations
>>
>> Compare this to if we used $-substitution:
>>
>> = $a + $b # With a=5, b=6 becomes "5 + 6"
>> = $a + $b # With a=10, b=6 becomes "10 + 6" -
>> different cache key!
>>
>> Every value change would create a new cache entry or
>> worse, a cache miss.
>>
>> Comparison to Other Approaches
>>
>> Tcl's expr: about 0.40 microseconds
>> Direct C evaluator: about 0.53 microseconds
>> Your cached approach: about 1.80 microseconds
>> Your uncached approach: about 24.9 microseconds
>>
>> With caching, you're only 3-4x slower than a direct C
>> evaluator.
>>
>>
>> My Assessment
>>
>> Your design is excellent. The bare variable feature isn't
>> just syntax sugar - it's essential for good cache
>> performance. The synergy between:
>>
>> 1. Bare variables leading to stable cache keys
>> 2. Runtime lookup keeping cache hot
>> 3. Simple caching providing dramatic speedup
>>
>> makes this really elegant.
>>
>> My recommendation: Keep it in Tcl! The implementation is
>> clean, performance is excellent (1.8 microseconds is
>> plenty fast), and converting to C would add significant
>> complexity for minimal gain (maybe getting to about 1.0
>> microseconds).
>>
>> The Tcl prototype with caching is actually the right
>> solution here. Sometimes the prototype IS the product!
>>
>> Excellent work on this. The bytecode approach really
>> shines with caching enabled.
>>
>> On Sun, Nov 2, 2025 at 10:14 AM Colin Macleod via
>> Tcl-Core <tcl...@li...> wrote:
>>
>> Hi again,
>>
>> I've now made a slightly more serious prototype, see
>> https://cmacleod.me.uk/tcl/expr_ng
>>
>> This is a modified version of the prototype I wrote
>> for tip 676. It's still in Tcl, but doesn't use
>> `expr`. It tokenises and parses the input, then
>> generates TAL bytecode and uses
>> ::tcl::unsupported::assemble to run that. A few
>> examples:
>>
>> (bin) 100 % set a [= 3.0/4]
>> 0.75
>> (bin) 101 % set b [= sin(a*10)]
>> 0.9379999767747389
>> (bin) 102 % set c [= (b-a)*100]
>> 18.79999767747389
>> (bin) 103 % namespace eval nn {set d [= 10**3]}
>> 1000
>> (bin) 104 % set e [= a?nn::d:b]
>> 1000
>> (bin) 105 % = {3 + [pwd]}
>> Calc: expected start of expression but found '[pwd]'
>> (bin) 106 % = {3 + $q}
>> Calc: expected start of expression but found '$q'
>> (bin) 107 % = sin (12)
>> -0.5365729180004349
>>
>> (bin) 108 % array set rr {one 1 two 2 three 3}
>> (bin) 110 % = a * rr(two)
>> Calc: expected operator but found '('
>> (bin) 111 % = a * $rr(two)
>> 1.5
>>
>> - You can use $ to get an array value substituted
>> before the `=` code sees the expression.
>>
>> (bin) 112 % string repeat ! [= nn::d / 15]
>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
>>
>> Colin.
>>
>> On 02/11/2025 09:04, Donal Fellows wrote:
>>> Doing the job properly would definitely involve
>>> changing the expression parser, with my suggested
>>> fix being to turn all bare words not otherwise
>>> recognised as constants or in positions that look
>>> like function calls (it's a parser with some
>>> lookahead) into simple variable reads (NB: C
>>> resolves such ambiguities within itself differently,
>>> but that's one of the nastiest parts of the
>>> language). We would need to retain $ support for
>>> resolving ambiguity (e.g., array reads vs function
>>> calls; you can't safely inspect the interpreter to
>>> resolve it at the time of compiling the expression
>>> due to traces and unknown handlers) as well as
>>> compatibility, but that's doable as it is a change
>>> only in cases that are currently errors.
>>>
>>> Adding assignment is quite a bit trickier, as that
>>> needs a new major syntax class to describe the left
>>> side of the assignment. I suggest omitting that from
>>> consideration at this stage.
>>>
>>> Donal.
>>>
>>> -------- Original message --------
>>> From: Colin Macleod via Tcl-Core
>>> <tcl...@li...>
>>> <mailto:tcl...@li...>
>>> Date: 02/11/2025 08:13 (GMT+00:00)
>>> To: Pietro Cerutti <ga...@ga...> <mailto:ga...@ga...>
>>> Cc: tcl...@li..., av...@lo...
>>> Subject: Re: [TCLCORE] Fwd: TIP 672 Implementation
>>> Complete - Ready for Sponsorship
>>>
>>> Indeed, this toy implementation doesn't handle that:
>>>
>>> % = sin (12)
>>> can't read "sin": no such variable
>>>
>>> I'm not sure that's serious, but it could be fixed
>>> in a C implementation.
>>>
>> _______________________________________________
>> 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
>
>
>
> _______________________________________________
> Tcl-Core mailing list
> Tcl...@li...
> https://lists.sourceforge.net/lists/listinfo/tcl-core |
|
From: EricT <tw...@gm...> - 2025-11-04 01:18:30
|
that is:
if {[info exist ::cache($exp)]} {
tailcall ::tcl::unsupported::assemble $::cache($exp)
}
(hate gmail!)
On Mon, Nov 3, 2025 at 5:17 PM EricT <tw...@gm...> wrote:
> and silly of me, it should be:
> if {[info exist ::cache($exp)]} {
> tailcall ::tcl::unsupported::assemble $::cache($exp)
> }
>
>
> On Mon, Nov 3, 2025 at 4:50 PM EricT <tw...@gm...> wrote:
>
>> With a debug line back in plus the tailcall:
>>
>> proc = args {
>> set exp [join $args]
>> if { [info exist ::cache($exp)] } {
>> return [tailcall ::tcl::unsupported::assemble $::cache($exp)]
>> }
>> set tokens [tokenise $exp]
>> deb1 "TOKENS = '$tokens'"
>> set code [compile $tokens]
>> deb1 "GENERATED CODE:\n$code\n"
>> puts "exp= |$exp| code= |$code| ifexist: [info exist ::cache($exp)]"
>> set ::cache($exp) $code
>> uplevel [list ::tcl::unsupported::assemble $code]
>> }
>>
>> % set a 5
>> 5
>> % set b 10
>> 10
>> % = a + b
>> exp= |a + b| code= |push a; loadStk; push b; loadStk; add; | ifexist: 0
>> 15
>> % = a + b
>> 15
>>
>> % time {= a + b} 1000
>> 1.73 microseconds per iteration
>>
>>
>> Faster still!
>>
>> I thought the uplevel was needed to be able to get the local variables,
>> seems not.
>>
>> % proc foo arg {set a 5; set b 10; set c [= a+b+arg]}
>> % foo 5
>> exp= |a+b+arg| code= |push a; loadStk; push b; loadStk; add; push arg;
>> loadStk; add; | ifexist: 0
>> 20
>> % foo 5
>> 20
>>
>> % proc foo arg {global xxx; set a 5; set b 10; set c [= a+b+arg+xxx]}
>>
>> % set xxx 100
>> 100
>> % foo 200
>> 315
>> % time {foo 200} 10000
>> 2.1775 microseconds per iteration
>>
>> % parray cache
>> cache(a + b) = push a; loadStk; push b; loadStk; add;
>> cache(a+b+arg) = push a; loadStk; push b; loadStk; add; push arg;
>> loadStk; add;
>> cache(a+b+arg+xxx) = push a; loadStk; push b; loadStk; add; push arg;
>> loadStk; add; push xxx; loadStk; add;
>>
>>
>> Very Impressive, great job Colin! Great catch Don!
>>
>> Eric
>>
>>
>>
>>
>> On Mon, Nov 3, 2025 at 4:22 PM Donald Porter via Tcl-Core <
>> tcl...@li...> wrote:
>>
>>> Check what effect replacing [uplevel] with [tailcall] has.
>>>
>>> On Nov 3, 2025, at 7:13 PM, EricT <tw...@gm...> wrote:
>>>
>>> Subject: Your bytecode expression evaluator - impressive results with
>>> caching!
>>>
>>> Hey Colin:
>>>
>>> I took a look at your bytecode-based expression evaluator and was
>>> intrigued by the approach. I made a small modification to add caching and
>>> the results are really impressive. Here's what I changed:
>>>
>>> proc = args {
>>> set exp [join $args]
>>> if {[info exist ::cache($exp)]} {
>>> return [uplevel [list ::tcl::unsupported::assemble
>>> $::cache($exp)]]
>>> }
>>> set tokens [tokenise $exp]
>>> deb1 "TOKENS = '$tokens'"
>>> set code [compile $tokens]
>>> deb1 "GENERATED CODE:\n$code\n"
>>> set ::cache($exp) $code
>>> uplevel [list ::tcl::unsupported::assemble $code]
>>> }
>>>
>>> The cache is just a simple array lookup - one line to store, one line to
>>> retrieve. But the performance impact is huge:
>>>
>>> Performance Tests
>>>
>>> Without caching
>>> % time {= 1 + 2} 1000
>>> 24.937 microseconds per iteration
>>>
>>> With caching
>>> % time {= 1 + 2} 1000
>>> 1.8 microseconds per iteration
>>>
>>> That's a 13x speedup! The tokenize and parse steps were eating about 92%
>>> of the execution time.
>>>
>>> The Real Magic: Bare Variables + Caching
>>>
>>> What really impressed me is how well your bare variable feature
>>> synergizes with caching:
>>>
>>> % set a 5
>>> 5
>>> % set b 6
>>> 6
>>> % = a + b
>>> 11
>>> % time {= a + b} 1000
>>> 2.079 microseconds per iteration
>>>
>>> Now change the variable values
>>> % set a 10
>>> 10
>>> % = a + b
>>> 16
>>> % time {= a + b} 1000
>>> 2.188 microseconds per iteration
>>>
>>> The cache entry stays valid even when the variable values change! Why?
>>> Because the bytecode stores variable names, not values:
>>>
>>> push a; loadStk; push b; loadStk; add;
>>>
>>> The loadStk instruction does runtime lookup, so:
>>> - Cache key is stable: "a + b"
>>> - Works for any values of a and b
>>> - One cache entry handles all value combinations
>>>
>>> Compare this to if we used $-substitution:
>>>
>>> = $a + $b # With a=5, b=6 becomes "5 + 6"
>>> = $a + $b # With a=10, b=6 becomes "10 + 6" - different cache key!
>>>
>>> Every value change would create a new cache entry or worse, a cache miss.
>>>
>>> Comparison to Other Approaches
>>>
>>> Tcl's expr: about 0.40 microseconds
>>> Direct C evaluator: about 0.53 microseconds
>>> Your cached approach: about 1.80 microseconds
>>> Your uncached approach: about 24.9 microseconds
>>>
>>> With caching, you're only 3-4x slower than a direct C evaluator.
>>>
>>>
>>> My Assessment
>>>
>>> Your design is excellent. The bare variable feature isn't just syntax
>>> sugar - it's essential for good cache performance. The synergy between:
>>>
>>> 1. Bare variables leading to stable cache keys
>>> 2. Runtime lookup keeping cache hot
>>> 3. Simple caching providing dramatic speedup
>>>
>>> makes this really elegant.
>>>
>>> My recommendation: Keep it in Tcl! The implementation is clean,
>>> performance is excellent (1.8 microseconds is plenty fast), and converting
>>> to C would add significant complexity for minimal gain (maybe getting to
>>> about 1.0 microseconds).
>>>
>>> The Tcl prototype with caching is actually the right solution here.
>>> Sometimes the prototype IS the product!
>>>
>>> Excellent work on this. The bytecode approach really shines with caching
>>> enabled.
>>>
>>> On Sun, Nov 2, 2025 at 10:14 AM Colin Macleod via Tcl-Core <
>>> tcl...@li...> wrote:
>>>
>>>> Hi again,
>>>>
>>>> I've now made a slightly more serious prototype, see
>>>> https://cmacleod.me.uk/tcl/expr_ng
>>>>
>>>> This is a modified version of the prototype I wrote for tip 676. It's
>>>> still in Tcl, but doesn't use `expr`. It tokenises and parses the input,
>>>> then generates TAL bytecode and uses ::tcl::unsupported::assemble to run
>>>> that. A few examples:
>>>>
>>>> (bin) 100 % set a [= 3.0/4]
>>>> 0.75
>>>> (bin) 101 % set b [= sin(a*10)]
>>>> 0.9379999767747389
>>>> (bin) 102 % set c [= (b-a)*100]
>>>> 18.79999767747389
>>>> (bin) 103 % namespace eval nn {set d [= 10**3]}
>>>> 1000
>>>> (bin) 104 % set e [= a?nn::d:b]
>>>> 1000
>>>> (bin) 105 % = {3 + [pwd]}
>>>> Calc: expected start of expression but found '[pwd]'
>>>> (bin) 106 % = {3 + $q}
>>>> Calc: expected start of expression but found '$q'
>>>> (bin) 107 % = sin (12)
>>>> -0.5365729180004349
>>>>
>>>> (bin) 108 % array set rr {one 1 two 2 three 3}
>>>> (bin) 110 % = a * rr(two)
>>>> Calc: expected operator but found '('
>>>> (bin) 111 % = a * $rr(two)
>>>> 1.5
>>>>
>>>> - You can use $ to get an array value substituted before the `=` code
>>>> sees the expression.
>>>>
>>>> (bin) 112 % string repeat ! [= nn::d / 15]
>>>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
>>>>
>>>> Colin.
>>>> On 02/11/2025 09:04, Donal Fellows wrote:
>>>>
>>>> Doing the job properly would definitely involve changing the expression
>>>> parser, with my suggested fix being to turn all bare words not otherwise
>>>> recognised as constants or in positions that look like function calls (it's
>>>> a parser with some lookahead) into simple variable reads (NB: C resolves
>>>> such ambiguities within itself differently, but that's one of the nastiest
>>>> parts of the language). We would need to retain $ support for resolving
>>>> ambiguity (e.g., array reads vs function calls; you can't safely inspect
>>>> the interpreter to resolve it at the time of compiling the expression due
>>>> to traces and unknown handlers) as well as compatibility, but that's doable
>>>> as it is a change only in cases that are currently errors.
>>>>
>>>> Adding assignment is quite a bit trickier, as that needs a new major
>>>> syntax class to describe the left side of the assignment. I suggest
>>>> omitting that from consideration at this stage.
>>>>
>>>> Donal.
>>>>
>>>> -------- Original message --------
>>>> From: Colin Macleod via Tcl-Core <tcl...@li...>
>>>> <tcl...@li...>
>>>> Date: 02/11/2025 08:13 (GMT+00:00)
>>>> To: Pietro Cerutti <ga...@ga...> <ga...@ga...>
>>>> Cc: tcl...@li..., av...@lo...
>>>> Subject: Re: [TCLCORE] Fwd: TIP 672 Implementation Complete - Ready for
>>>> Sponsorship
>>>>
>>>> Indeed, this toy implementation doesn't handle that:
>>>>
>>>> % = sin (12)
>>>> can't read "sin": no such variable
>>>>
>>>> I'm not sure that's serious, but it could be fixed in a C
>>>> implementation.
>>>>
>>>> _______________________________________________
>>>> 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: EricT <tw...@gm...> - 2025-11-04 01:17:28
|
and silly of me, it should be:
if {[info exist ::cache($exp)]} {
tailcall ::tcl::unsupported::assemble $::cache($exp)
}
On Mon, Nov 3, 2025 at 4:50 PM EricT <tw...@gm...> wrote:
> With a debug line back in plus the tailcall:
>
> proc = args {
> set exp [join $args]
> if { [info exist ::cache($exp)] } {
> return [tailcall ::tcl::unsupported::assemble $::cache($exp)]
> }
> set tokens [tokenise $exp]
> deb1 "TOKENS = '$tokens'"
> set code [compile $tokens]
> deb1 "GENERATED CODE:\n$code\n"
> puts "exp= |$exp| code= |$code| ifexist: [info exist ::cache($exp)]"
> set ::cache($exp) $code
> uplevel [list ::tcl::unsupported::assemble $code]
> }
>
> % set a 5
> 5
> % set b 10
> 10
> % = a + b
> exp= |a + b| code= |push a; loadStk; push b; loadStk; add; | ifexist: 0
> 15
> % = a + b
> 15
>
> % time {= a + b} 1000
> 1.73 microseconds per iteration
>
>
> Faster still!
>
> I thought the uplevel was needed to be able to get the local variables,
> seems not.
>
> % proc foo arg {set a 5; set b 10; set c [= a+b+arg]}
> % foo 5
> exp= |a+b+arg| code= |push a; loadStk; push b; loadStk; add; push arg;
> loadStk; add; | ifexist: 0
> 20
> % foo 5
> 20
>
> % proc foo arg {global xxx; set a 5; set b 10; set c [= a+b+arg+xxx]}
>
> % set xxx 100
> 100
> % foo 200
> 315
> % time {foo 200} 10000
> 2.1775 microseconds per iteration
>
> % parray cache
> cache(a + b) = push a; loadStk; push b; loadStk; add;
> cache(a+b+arg) = push a; loadStk; push b; loadStk; add; push arg;
> loadStk; add;
> cache(a+b+arg+xxx) = push a; loadStk; push b; loadStk; add; push arg;
> loadStk; add; push xxx; loadStk; add;
>
>
> Very Impressive, great job Colin! Great catch Don!
>
> Eric
>
>
>
>
> On Mon, Nov 3, 2025 at 4:22 PM Donald Porter via Tcl-Core <
> tcl...@li...> wrote:
>
>> Check what effect replacing [uplevel] with [tailcall] has.
>>
>> On Nov 3, 2025, at 7:13 PM, EricT <tw...@gm...> wrote:
>>
>> Subject: Your bytecode expression evaluator - impressive results with
>> caching!
>>
>> Hey Colin:
>>
>> I took a look at your bytecode-based expression evaluator and was
>> intrigued by the approach. I made a small modification to add caching and
>> the results are really impressive. Here's what I changed:
>>
>> proc = args {
>> set exp [join $args]
>> if {[info exist ::cache($exp)]} {
>> return [uplevel [list ::tcl::unsupported::assemble
>> $::cache($exp)]]
>> }
>> set tokens [tokenise $exp]
>> deb1 "TOKENS = '$tokens'"
>> set code [compile $tokens]
>> deb1 "GENERATED CODE:\n$code\n"
>> set ::cache($exp) $code
>> uplevel [list ::tcl::unsupported::assemble $code]
>> }
>>
>> The cache is just a simple array lookup - one line to store, one line to
>> retrieve. But the performance impact is huge:
>>
>> Performance Tests
>>
>> Without caching
>> % time {= 1 + 2} 1000
>> 24.937 microseconds per iteration
>>
>> With caching
>> % time {= 1 + 2} 1000
>> 1.8 microseconds per iteration
>>
>> That's a 13x speedup! The tokenize and parse steps were eating about 92%
>> of the execution time.
>>
>> The Real Magic: Bare Variables + Caching
>>
>> What really impressed me is how well your bare variable feature
>> synergizes with caching:
>>
>> % set a 5
>> 5
>> % set b 6
>> 6
>> % = a + b
>> 11
>> % time {= a + b} 1000
>> 2.079 microseconds per iteration
>>
>> Now change the variable values
>> % set a 10
>> 10
>> % = a + b
>> 16
>> % time {= a + b} 1000
>> 2.188 microseconds per iteration
>>
>> The cache entry stays valid even when the variable values change! Why?
>> Because the bytecode stores variable names, not values:
>>
>> push a; loadStk; push b; loadStk; add;
>>
>> The loadStk instruction does runtime lookup, so:
>> - Cache key is stable: "a + b"
>> - Works for any values of a and b
>> - One cache entry handles all value combinations
>>
>> Compare this to if we used $-substitution:
>>
>> = $a + $b # With a=5, b=6 becomes "5 + 6"
>> = $a + $b # With a=10, b=6 becomes "10 + 6" - different cache key!
>>
>> Every value change would create a new cache entry or worse, a cache miss.
>>
>> Comparison to Other Approaches
>>
>> Tcl's expr: about 0.40 microseconds
>> Direct C evaluator: about 0.53 microseconds
>> Your cached approach: about 1.80 microseconds
>> Your uncached approach: about 24.9 microseconds
>>
>> With caching, you're only 3-4x slower than a direct C evaluator.
>>
>>
>> My Assessment
>>
>> Your design is excellent. The bare variable feature isn't just syntax
>> sugar - it's essential for good cache performance. The synergy between:
>>
>> 1. Bare variables leading to stable cache keys
>> 2. Runtime lookup keeping cache hot
>> 3. Simple caching providing dramatic speedup
>>
>> makes this really elegant.
>>
>> My recommendation: Keep it in Tcl! The implementation is clean,
>> performance is excellent (1.8 microseconds is plenty fast), and converting
>> to C would add significant complexity for minimal gain (maybe getting to
>> about 1.0 microseconds).
>>
>> The Tcl prototype with caching is actually the right solution here.
>> Sometimes the prototype IS the product!
>>
>> Excellent work on this. The bytecode approach really shines with caching
>> enabled.
>>
>> On Sun, Nov 2, 2025 at 10:14 AM Colin Macleod via Tcl-Core <
>> tcl...@li...> wrote:
>>
>>> Hi again,
>>>
>>> I've now made a slightly more serious prototype, see
>>> https://cmacleod.me.uk/tcl/expr_ng
>>>
>>> This is a modified version of the prototype I wrote for tip 676. It's
>>> still in Tcl, but doesn't use `expr`. It tokenises and parses the input,
>>> then generates TAL bytecode and uses ::tcl::unsupported::assemble to run
>>> that. A few examples:
>>>
>>> (bin) 100 % set a [= 3.0/4]
>>> 0.75
>>> (bin) 101 % set b [= sin(a*10)]
>>> 0.9379999767747389
>>> (bin) 102 % set c [= (b-a)*100]
>>> 18.79999767747389
>>> (bin) 103 % namespace eval nn {set d [= 10**3]}
>>> 1000
>>> (bin) 104 % set e [= a?nn::d:b]
>>> 1000
>>> (bin) 105 % = {3 + [pwd]}
>>> Calc: expected start of expression but found '[pwd]'
>>> (bin) 106 % = {3 + $q}
>>> Calc: expected start of expression but found '$q'
>>> (bin) 107 % = sin (12)
>>> -0.5365729180004349
>>>
>>> (bin) 108 % array set rr {one 1 two 2 three 3}
>>> (bin) 110 % = a * rr(two)
>>> Calc: expected operator but found '('
>>> (bin) 111 % = a * $rr(two)
>>> 1.5
>>>
>>> - You can use $ to get an array value substituted before the `=` code
>>> sees the expression.
>>>
>>> (bin) 112 % string repeat ! [= nn::d / 15]
>>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
>>>
>>> Colin.
>>> On 02/11/2025 09:04, Donal Fellows wrote:
>>>
>>> Doing the job properly would definitely involve changing the expression
>>> parser, with my suggested fix being to turn all bare words not otherwise
>>> recognised as constants or in positions that look like function calls (it's
>>> a parser with some lookahead) into simple variable reads (NB: C resolves
>>> such ambiguities within itself differently, but that's one of the nastiest
>>> parts of the language). We would need to retain $ support for resolving
>>> ambiguity (e.g., array reads vs function calls; you can't safely inspect
>>> the interpreter to resolve it at the time of compiling the expression due
>>> to traces and unknown handlers) as well as compatibility, but that's doable
>>> as it is a change only in cases that are currently errors.
>>>
>>> Adding assignment is quite a bit trickier, as that needs a new major
>>> syntax class to describe the left side of the assignment. I suggest
>>> omitting that from consideration at this stage.
>>>
>>> Donal.
>>>
>>> -------- Original message --------
>>> From: Colin Macleod via Tcl-Core <tcl...@li...>
>>> <tcl...@li...>
>>> Date: 02/11/2025 08:13 (GMT+00:00)
>>> To: Pietro Cerutti <ga...@ga...> <ga...@ga...>
>>> Cc: tcl...@li..., av...@lo...
>>> Subject: Re: [TCLCORE] Fwd: TIP 672 Implementation Complete - Ready for
>>> Sponsorship
>>>
>>> Indeed, this toy implementation doesn't handle that:
>>>
>>> % = sin (12)
>>> can't read "sin": no such variable
>>>
>>> I'm not sure that's serious, but it could be fixed in a C implementation.
>>>
>>> _______________________________________________
>>> 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: EricT <tw...@gm...> - 2025-11-04 00:50:54
|
With a debug line back in plus the tailcall:
proc = args {
set exp [join $args]
if { [info exist ::cache($exp)] } {
return [tailcall ::tcl::unsupported::assemble $::cache($exp)]
}
set tokens [tokenise $exp]
deb1 "TOKENS = '$tokens'"
set code [compile $tokens]
deb1 "GENERATED CODE:\n$code\n"
puts "exp= |$exp| code= |$code| ifexist: [info exist ::cache($exp)]"
set ::cache($exp) $code
uplevel [list ::tcl::unsupported::assemble $code]
}
% set a 5
5
% set b 10
10
% = a + b
exp= |a + b| code= |push a; loadStk; push b; loadStk; add; | ifexist: 0
15
% = a + b
15
% time {= a + b} 1000
1.73 microseconds per iteration
Faster still!
I thought the uplevel was needed to be able to get the local variables,
seems not.
% proc foo arg {set a 5; set b 10; set c [= a+b+arg]}
% foo 5
exp= |a+b+arg| code= |push a; loadStk; push b; loadStk; add; push arg;
loadStk; add; | ifexist: 0
20
% foo 5
20
% proc foo arg {global xxx; set a 5; set b 10; set c [= a+b+arg+xxx]}
% set xxx 100
100
% foo 200
315
% time {foo 200} 10000
2.1775 microseconds per iteration
% parray cache
cache(a + b) = push a; loadStk; push b; loadStk; add;
cache(a+b+arg) = push a; loadStk; push b; loadStk; add; push arg;
loadStk; add;
cache(a+b+arg+xxx) = push a; loadStk; push b; loadStk; add; push arg;
loadStk; add; push xxx; loadStk; add;
Very Impressive, great job Colin! Great catch Don!
Eric
On Mon, Nov 3, 2025 at 4:22 PM Donald Porter via Tcl-Core <
tcl...@li...> wrote:
> Check what effect replacing [uplevel] with [tailcall] has.
>
> On Nov 3, 2025, at 7:13 PM, EricT <tw...@gm...> wrote:
>
> Subject: Your bytecode expression evaluator - impressive results with
> caching!
>
> Hey Colin:
>
> I took a look at your bytecode-based expression evaluator and was
> intrigued by the approach. I made a small modification to add caching and
> the results are really impressive. Here's what I changed:
>
> proc = args {
> set exp [join $args]
> if {[info exist ::cache($exp)]} {
> return [uplevel [list ::tcl::unsupported::assemble $::cache($exp)]]
> }
> set tokens [tokenise $exp]
> deb1 "TOKENS = '$tokens'"
> set code [compile $tokens]
> deb1 "GENERATED CODE:\n$code\n"
> set ::cache($exp) $code
> uplevel [list ::tcl::unsupported::assemble $code]
> }
>
> The cache is just a simple array lookup - one line to store, one line to
> retrieve. But the performance impact is huge:
>
> Performance Tests
>
> Without caching
> % time {= 1 + 2} 1000
> 24.937 microseconds per iteration
>
> With caching
> % time {= 1 + 2} 1000
> 1.8 microseconds per iteration
>
> That's a 13x speedup! The tokenize and parse steps were eating about 92%
> of the execution time.
>
> The Real Magic: Bare Variables + Caching
>
> What really impressed me is how well your bare variable feature synergizes
> with caching:
>
> % set a 5
> 5
> % set b 6
> 6
> % = a + b
> 11
> % time {= a + b} 1000
> 2.079 microseconds per iteration
>
> Now change the variable values
> % set a 10
> 10
> % = a + b
> 16
> % time {= a + b} 1000
> 2.188 microseconds per iteration
>
> The cache entry stays valid even when the variable values change! Why?
> Because the bytecode stores variable names, not values:
>
> push a; loadStk; push b; loadStk; add;
>
> The loadStk instruction does runtime lookup, so:
> - Cache key is stable: "a + b"
> - Works for any values of a and b
> - One cache entry handles all value combinations
>
> Compare this to if we used $-substitution:
>
> = $a + $b # With a=5, b=6 becomes "5 + 6"
> = $a + $b # With a=10, b=6 becomes "10 + 6" - different cache key!
>
> Every value change would create a new cache entry or worse, a cache miss.
>
> Comparison to Other Approaches
>
> Tcl's expr: about 0.40 microseconds
> Direct C evaluator: about 0.53 microseconds
> Your cached approach: about 1.80 microseconds
> Your uncached approach: about 24.9 microseconds
>
> With caching, you're only 3-4x slower than a direct C evaluator.
>
>
> My Assessment
>
> Your design is excellent. The bare variable feature isn't just syntax
> sugar - it's essential for good cache performance. The synergy between:
>
> 1. Bare variables leading to stable cache keys
> 2. Runtime lookup keeping cache hot
> 3. Simple caching providing dramatic speedup
>
> makes this really elegant.
>
> My recommendation: Keep it in Tcl! The implementation is clean,
> performance is excellent (1.8 microseconds is plenty fast), and converting
> to C would add significant complexity for minimal gain (maybe getting to
> about 1.0 microseconds).
>
> The Tcl prototype with caching is actually the right solution here.
> Sometimes the prototype IS the product!
>
> Excellent work on this. The bytecode approach really shines with caching
> enabled.
>
> On Sun, Nov 2, 2025 at 10:14 AM Colin Macleod via Tcl-Core <
> tcl...@li...> wrote:
>
>> Hi again,
>>
>> I've now made a slightly more serious prototype, see
>> https://cmacleod.me.uk/tcl/expr_ng
>>
>> This is a modified version of the prototype I wrote for tip 676. It's
>> still in Tcl, but doesn't use `expr`. It tokenises and parses the input,
>> then generates TAL bytecode and uses ::tcl::unsupported::assemble to run
>> that. A few examples:
>>
>> (bin) 100 % set a [= 3.0/4]
>> 0.75
>> (bin) 101 % set b [= sin(a*10)]
>> 0.9379999767747389
>> (bin) 102 % set c [= (b-a)*100]
>> 18.79999767747389
>> (bin) 103 % namespace eval nn {set d [= 10**3]}
>> 1000
>> (bin) 104 % set e [= a?nn::d:b]
>> 1000
>> (bin) 105 % = {3 + [pwd]}
>> Calc: expected start of expression but found '[pwd]'
>> (bin) 106 % = {3 + $q}
>> Calc: expected start of expression but found '$q'
>> (bin) 107 % = sin (12)
>> -0.5365729180004349
>>
>> (bin) 108 % array set rr {one 1 two 2 three 3}
>> (bin) 110 % = a * rr(two)
>> Calc: expected operator but found '('
>> (bin) 111 % = a * $rr(two)
>> 1.5
>>
>> - You can use $ to get an array value substituted before the `=` code
>> sees the expression.
>>
>> (bin) 112 % string repeat ! [= nn::d / 15]
>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
>>
>> Colin.
>> On 02/11/2025 09:04, Donal Fellows wrote:
>>
>> Doing the job properly would definitely involve changing the expression
>> parser, with my suggested fix being to turn all bare words not otherwise
>> recognised as constants or in positions that look like function calls (it's
>> a parser with some lookahead) into simple variable reads (NB: C resolves
>> such ambiguities within itself differently, but that's one of the nastiest
>> parts of the language). We would need to retain $ support for resolving
>> ambiguity (e.g., array reads vs function calls; you can't safely inspect
>> the interpreter to resolve it at the time of compiling the expression due
>> to traces and unknown handlers) as well as compatibility, but that's doable
>> as it is a change only in cases that are currently errors.
>>
>> Adding assignment is quite a bit trickier, as that needs a new major
>> syntax class to describe the left side of the assignment. I suggest
>> omitting that from consideration at this stage.
>>
>> Donal.
>>
>> -------- Original message --------
>> From: Colin Macleod via Tcl-Core <tcl...@li...>
>> <tcl...@li...>
>> Date: 02/11/2025 08:13 (GMT+00:00)
>> To: Pietro Cerutti <ga...@ga...> <ga...@ga...>
>> Cc: tcl...@li..., av...@lo...
>> Subject: Re: [TCLCORE] Fwd: TIP 672 Implementation Complete - Ready for
>> Sponsorship
>>
>> Indeed, this toy implementation doesn't handle that:
>>
>> % = sin (12)
>> can't read "sin": no such variable
>>
>> I'm not sure that's serious, but it could be fixed in a C implementation.
>>
>> _______________________________________________
>> 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: Donald P. <d.g...@co...> - 2025-11-04 00:22:42
|
Check what effect replacing [uplevel] with [tailcall] has.
> On Nov 3, 2025, at 7:13 PM, EricT <tw...@gm...> wrote:
>
> Subject: Your bytecode expression evaluator - impressive results with caching!
>
> Hey Colin:
>
> I took a look at your bytecode-based expression evaluator and was intrigued by the approach. I made a small modification to add caching and the results are really impressive. Here's what I changed:
>
> proc = args {
> set exp [join $args]
> if {[info exist ::cache($exp)]} {
> return [uplevel [list ::tcl::unsupported::assemble $::cache($exp)]]
> }
> set tokens [tokenise $exp]
> deb1 "TOKENS = '$tokens'"
> set code [compile $tokens]
> deb1 "GENERATED CODE:\n$code\n"
> set ::cache($exp) $code
> uplevel [list ::tcl::unsupported::assemble $code]
> }
>
> The cache is just a simple array lookup - one line to store, one line to retrieve. But the performance impact is huge:
>
> Performance Tests
>
> Without caching
> % time {= 1 + 2} 1000
> 24.937 microseconds per iteration
>
> With caching
> % time {= 1 + 2} 1000
> 1.8 microseconds per iteration
>
> That's a 13x speedup! The tokenize and parse steps were eating about 92% of the execution time.
>
> The Real Magic: Bare Variables + Caching
>
> What really impressed me is how well your bare variable feature synergizes with caching:
>
> % set a 5
> 5
> % set b 6
> 6
> % = a + b
> 11
> % time {= a + b} 1000
> 2.079 microseconds per iteration
>
> Now change the variable values
> % set a 10
> 10
> % = a + b
> 16
> % time {= a + b} 1000
> 2.188 microseconds per iteration
>
> The cache entry stays valid even when the variable values change! Why? Because the bytecode stores variable names, not values:
>
> push a; loadStk; push b; loadStk; add;
>
> The loadStk instruction does runtime lookup, so:
> - Cache key is stable: "a + b"
> - Works for any values of a and b
> - One cache entry handles all value combinations
>
> Compare this to if we used $-substitution:
>
> = $a + $b # With a=5, b=6 becomes "5 + 6"
> = $a + $b # With a=10, b=6 becomes "10 + 6" - different cache key!
>
> Every value change would create a new cache entry or worse, a cache miss.
>
> Comparison to Other Approaches
>
> Tcl's expr: about 0.40 microseconds
> Direct C evaluator: about 0.53 microseconds
> Your cached approach: about 1.80 microseconds
> Your uncached approach: about 24.9 microseconds
>
> With caching, you're only 3-4x slower than a direct C evaluator.
>
>
> My Assessment
>
> Your design is excellent. The bare variable feature isn't just syntax sugar - it's essential for good cache performance. The synergy between:
>
> 1. Bare variables leading to stable cache keys
> 2. Runtime lookup keeping cache hot
> 3. Simple caching providing dramatic speedup
>
> makes this really elegant.
>
> My recommendation: Keep it in Tcl! The implementation is clean, performance is excellent (1.8 microseconds is plenty fast), and converting to C would add significant complexity for minimal gain (maybe getting to about 1.0 microseconds).
>
> The Tcl prototype with caching is actually the right solution here. Sometimes the prototype IS the product!
>
> Excellent work on this. The bytecode approach really shines with caching enabled.
>
> On Sun, Nov 2, 2025 at 10:14 AM Colin Macleod via Tcl-Core <tcl...@li... <mailto:tcl...@li...>> wrote:
>> Hi again,
>>
>> I've now made a slightly more serious prototype, see https://cmacleod.me.uk/tcl/expr_ng
>>
>> This is a modified version of the prototype I wrote for tip 676. It's still in Tcl, but doesn't use `expr`. It tokenises and parses the input, then generates TAL bytecode and uses ::tcl::unsupported::assemble to run that. A few examples:
>>
>> (bin) 100 % set a [= 3.0/4]
>> 0.75
>> (bin) 101 % set b [= sin(a*10)]
>> 0.9379999767747389
>> (bin) 102 % set c [= (b-a)*100]
>> 18.79999767747389
>> (bin) 103 % namespace eval nn {set d [= 10**3]}
>> 1000
>> (bin) 104 % set e [= a?nn::d:b]
>> 1000
>> (bin) 105 % = {3 + [pwd]}
>> Calc: expected start of expression but found '[pwd]'
>> (bin) 106 % = {3 + $q}
>> Calc: expected start of expression but found '$q'
>> (bin) 107 % = sin (12)
>> -0.5365729180004349
>>
>> (bin) 108 % array set rr {one 1 two 2 three 3}
>> (bin) 110 % = a * rr(two)
>> Calc: expected operator but found '('
>> (bin) 111 % = a * $rr(two)
>> 1.5
>>
>> - You can use $ to get an array value substituted before the `=` code sees the expression.
>>
>> (bin) 112 % string repeat ! [= nn::d / 15]
>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
>>
>> Colin.
>>
>> On 02/11/2025 09:04, Donal Fellows wrote:
>>> Doing the job properly would definitely involve changing the expression parser, with my suggested fix being to turn all bare words not otherwise recognised as constants or in positions that look like function calls (it's a parser with some lookahead) into simple variable reads (NB: C resolves such ambiguities within itself differently, but that's one of the nastiest parts of the language). We would need to retain $ support for resolving ambiguity (e.g., array reads vs function calls; you can't safely inspect the interpreter to resolve it at the time of compiling the expression due to traces and unknown handlers) as well as compatibility, but that's doable as it is a change only in cases that are currently errors.
>>>
>>> Adding assignment is quite a bit trickier, as that needs a new major syntax class to describe the left side of the assignment. I suggest omitting that from consideration at this stage.
>>>
>>> Donal.
>>>
>>> -------- Original message --------
>>> From: Colin Macleod via Tcl-Core <tcl...@li...> <mailto:tcl...@li...>
>>> Date: 02/11/2025 08:13 (GMT+00:00)
>>> To: Pietro Cerutti <ga...@ga...> <mailto:ga...@ga...>
>>> Cc: tcl...@li... <mailto:tcl...@li...>, av...@lo... <mailto:av...@lo...>
>>> Subject: Re: [TCLCORE] Fwd: TIP 672 Implementation Complete - Ready for Sponsorship
>>>
>>> Indeed, this toy implementation doesn't handle that:
>>>
>>> % = sin (12)
>>> can't read "sin": no such variable
>>>
>>> I'm not sure that's serious, but it could be fixed in a C implementation.
>>>
>> _______________________________________________
>> Tcl-Core mailing list
>> Tcl...@li... <mailto: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: EricT <tw...@gm...> - 2025-11-04 00:13:26
|
Subject: Your bytecode expression evaluator - impressive results with
caching!
Hey Colin:
I took a look at your bytecode-based expression evaluator and was intrigued
by the approach. I made a small modification to add caching and the results
are really impressive. Here's what I changed:
proc = args {
set exp [join $args]
if {[info exist ::cache($exp)]} {
return [uplevel [list ::tcl::unsupported::assemble $::cache($exp)]]
}
set tokens [tokenise $exp]
deb1 "TOKENS = '$tokens'"
set code [compile $tokens]
deb1 "GENERATED CODE:\n$code\n"
set ::cache($exp) $code
uplevel [list ::tcl::unsupported::assemble $code]
}
The cache is just a simple array lookup - one line to store, one line to
retrieve. But the performance impact is huge:
Performance Tests
Without caching
% time {= 1 + 2} 1000
24.937 microseconds per iteration
With caching
% time {= 1 + 2} 1000
1.8 microseconds per iteration
That's a 13x speedup! The tokenize and parse steps were eating about 92% of
the execution time.
The Real Magic: Bare Variables + Caching
What really impressed me is how well your bare variable feature synergizes
with caching:
% set a 5
5
% set b 6
6
% = a + b
11
% time {= a + b} 1000
2.079 microseconds per iteration
Now change the variable values
% set a 10
10
% = a + b
16
% time {= a + b} 1000
2.188 microseconds per iteration
The cache entry stays valid even when the variable values change! Why?
Because the bytecode stores variable names, not values:
push a; loadStk; push b; loadStk; add;
The loadStk instruction does runtime lookup, so:
- Cache key is stable: "a + b"
- Works for any values of a and b
- One cache entry handles all value combinations
Compare this to if we used $-substitution:
= $a + $b # With a=5, b=6 becomes "5 + 6"
= $a + $b # With a=10, b=6 becomes "10 + 6" - different cache key!
Every value change would create a new cache entry or worse, a cache miss.
Comparison to Other Approaches
Tcl's expr: about 0.40 microseconds
Direct C evaluator: about 0.53 microseconds
Your cached approach: about 1.80 microseconds
Your uncached approach: about 24.9 microseconds
With caching, you're only 3-4x slower than a direct C evaluator.
My Assessment
Your design is excellent. The bare variable feature isn't just syntax sugar
- it's essential for good cache performance. The synergy between:
1. Bare variables leading to stable cache keys
2. Runtime lookup keeping cache hot
3. Simple caching providing dramatic speedup
makes this really elegant.
My recommendation: Keep it in Tcl! The implementation is clean, performance
is excellent (1.8 microseconds is plenty fast), and converting to C would
add significant complexity for minimal gain (maybe getting to about 1.0
microseconds).
The Tcl prototype with caching is actually the right solution here.
Sometimes the prototype IS the product!
Excellent work on this. The bytecode approach really shines with caching
enabled.
On Sun, Nov 2, 2025 at 10:14 AM Colin Macleod via Tcl-Core <
tcl...@li...> wrote:
> Hi again,
>
> I've now made a slightly more serious prototype, see
> https://cmacleod.me.uk/tcl/expr_ng
>
> This is a modified version of the prototype I wrote for tip 676. It's
> still in Tcl, but doesn't use `expr`. It tokenises and parses the input,
> then generates TAL bytecode and uses ::tcl::unsupported::assemble to run
> that. A few examples:
>
> (bin) 100 % set a [= 3.0/4]
> 0.75
> (bin) 101 % set b [= sin(a*10)]
> 0.9379999767747389
> (bin) 102 % set c [= (b-a)*100]
> 18.79999767747389
> (bin) 103 % namespace eval nn {set d [= 10**3]}
> 1000
> (bin) 104 % set e [= a?nn::d:b]
> 1000
> (bin) 105 % = {3 + [pwd]}
> Calc: expected start of expression but found '[pwd]'
> (bin) 106 % = {3 + $q}
> Calc: expected start of expression but found '$q'
> (bin) 107 % = sin (12)
> -0.5365729180004349
>
> (bin) 108 % array set rr {one 1 two 2 three 3}
> (bin) 110 % = a * rr(two)
> Calc: expected operator but found '('
> (bin) 111 % = a * $rr(two)
> 1.5
>
> - You can use $ to get an array value substituted before the `=` code sees
> the expression.
>
> (bin) 112 % string repeat ! [= nn::d / 15]
> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
>
> Colin.
> On 02/11/2025 09:04, Donal Fellows wrote:
>
> Doing the job properly would definitely involve changing the expression
> parser, with my suggested fix being to turn all bare words not otherwise
> recognised as constants or in positions that look like function calls (it's
> a parser with some lookahead) into simple variable reads (NB: C resolves
> such ambiguities within itself differently, but that's one of the nastiest
> parts of the language). We would need to retain $ support for resolving
> ambiguity (e.g., array reads vs function calls; you can't safely inspect
> the interpreter to resolve it at the time of compiling the expression due
> to traces and unknown handlers) as well as compatibility, but that's doable
> as it is a change only in cases that are currently errors.
>
> Adding assignment is quite a bit trickier, as that needs a new major
> syntax class to describe the left side of the assignment. I suggest
> omitting that from consideration at this stage.
>
> Donal.
>
> -------- Original message --------
> From: Colin Macleod via Tcl-Core <tcl...@li...>
> <tcl...@li...>
> Date: 02/11/2025 08:13 (GMT+00:00)
> To: Pietro Cerutti <ga...@ga...> <ga...@ga...>
> Cc: tcl...@li..., av...@lo...
> Subject: Re: [TCLCORE] Fwd: TIP 672 Implementation Complete - Ready for
> Sponsorship
>
> Indeed, this toy implementation doesn't handle that:
>
> % = sin (12)
> can't read "sin": no such variable
>
> I'm not sure that's serious, but it could be fixed in a C implementation.
>
> _______________________________________________
> Tcl-Core mailing list
> Tcl...@li...
> https://lists.sourceforge.net/lists/listinfo/tcl-core
>
|
|
From: EricT <tw...@gm...> - 2025-11-03 21:29:13
|
Hi Ashok, Thank you for the positive feedback and the excellent questions. I should clarify - I did not write this code originally. It has been available on the Tcl wiki for quite some time. The original version worked via a puts rename and wrapper. After Tcl 8.6, someone (whose name I unfortunately don't know) added a two-way branch: one using channel transforms for 8.6+, and the legacy puts rename method for earlier versions. For years, I would force the rename method after discovering the channel code wouldn't correctly handle Unicode which breaks some of my debugging tools. When I wrote the TIP, I had forgotten about the Unicode problem and so didn't pursue it further. When I finally hit on the fix (the encoding convertfrom), I shared it here, and then through some recent testing fixed the open/close cycling issues. That's where we stand today. Regarding stdin from both terminal and console: I hadn't considered potential confusion for users or issues with event-driven async I/O from stdin. That's a good point worth investigating. In my testing, it simply worked as a convenience - type in either place - but I haven't tested complex async scenarios. As for reflected channels instead of transforms - my only knowledge of channel transforms comes from your book, but that's a rather advanced subject and I don't claim to understand it fully. My contribution was essentially finding and fixing the Unicode bug through trial and error. If reflected channels would be a better approach, I'd be happy to learn more, though implementing that would likely be beyond my current expertise. The main reason I wrote this TIP was to address the concern in the original code comments: it uses "semi-public" Tk internals with "some risk that future versions of Tk will no longer support this." Making it official would protect this functionality going forward. I'm very encouraged that you see potential for improving the Windows implementation as well! Eric On Mon, Nov 3, 2025 at 9:05 AM apnmbx-public--- via Tcl-Core < tcl...@li...> wrote: > Eric, > > > > That was my question – the fact that stdin comes from both console and > terminal. Whether that could cause confusion for users and also for event > driven async io from stdin? > > > > BTW, I like the model better than the current Windows implementation as > the latter is not a real channel and missing event driven io for one. May > be worth moving Windows to this implementation as well. > > > > Did you consider use of reflected channels instead of reflected transforms? > > > > /Ashok > > > > *From:* EricT <tw...@gm...> > > > > In my testing, via a source console.tcl, it does in fact allow input both > from the console and the terminal. It even works with rlwrap. What I fixed > in the most recent version is the opening and closing of the console > window. While the console window is open, no prompts go to the terminal, > however. But you can type in commands and the output will go to the console > window. > > > > > > _______________________________________________ > Tcl-Core mailing list > Tcl...@li... > https://lists.sourceforge.net/lists/listinfo/tcl-core > |
|
From: <apn...@ya...> - 2025-11-03 17:04:54
|
Eric, That was my question – the fact that stdin comes from both console and terminal. Whether that could cause confusion for users and also for event driven async io from stdin? BTW, I like the model better than the current Windows implementation as the latter is not a real channel and missing event driven io for one. May be worth moving Windows to this implementation as well. Did you consider use of reflected channels instead of reflected transforms? /Ashok From: EricT <tw...@gm...> In my testing, via a source console.tcl, it does in fact allow input both from the console and the terminal. It even works with rlwrap. What I fixed in the most recent version is the opening and closing of the console window. While the console window is open, no prompts go to the terminal, however. But you can type in commands and the output will go to the console window. |
|
From: <apn...@ya...> - 2025-11-03 16:57:03
|
Marc, >From my reading of the code, the default search path on macOS is set through the $tclDefaultLibrary variable in TclpSetVariables <https://core.tcl-lang.org/tcl/file?ci=4ed06667a6d2d9fb&name=unix%2FtclUnixInit.c&ln=790> . This is *purportedly* unchanged in TIP 732 which includes it as step (2d). Of course, like politicians, TIP’s may say one thing and do another so I need to check that. Another possibility is the test run itself installs the library in locations that are not in the new search path (in particular, ancestor directories or directories without version components). In which case the test run needs to be fixed. Nought to do but iterate through github action runs and examine logs. Oh joy Thanks for the notes on build possibilities for my own edification. BTW, when you say “in the past”, I presume you mean 9.0 (as in pre-TIP732) ? From: Marc Culler <cul...@gm...> Sent: Monday, November 3, 2025 6:29 PM To: Jan Nijtmans <jan...@gm...> Cc: tcl...@li... Subject: Re: [TCLCORE] TIP 732 ready for comments It is not clear to me from the TIP what the default search path would be for macOS. However, macOS is not a single platform in this context. It can be built two ways: (1) a framework build, which installs in /Library/Frameworks/Tcl.framework (and an analogous Library/Frameworks/Tk.framework. (2) a "prefix" build, which installs in <prefix>/{bin,lib.include,share} In the past the default search path accommodated both build types. For a framework build of Tcl X.Y, init.tcl was installed in: /Library/Frameworks/Tcl.framework/Versions/X.Y/Resources/Scripts/ and that was also a place where third party packages could be installed. (By the way this is a good way to handle different versions of Tcl and Tk.) For a prefix build I believe that the install policy was the same as for other unix systems. However, other directories were included in the search path on macOS. These included /Library/Tcl and / or /Library/Tcl/X.Y. In addition there was a notion that a user might install a Tcl.framework in their personal Library directory. So another location was $HOME/Library/Frameworks/Tcl.framework/Versions/X.Y/Resources/Scripts. Incidentally Apple's (flexible) rules for how files should be arranged in a framework specify that executable scripts should go in the Resources directory. However this conflicts with the fact that while some extension packages contain only scripts, others contain dynamic libraries. However, there seems to be no problem with installing a package that has a dynamic library into /Library/Frameworks/Tcl.framework/Versions/X.Y/Resources/Scriopts. - Marc On Mon, Nov 3, 2025 at 4:29 AM Jan Nijtmans <jan...@gm... <mailto:jan...@gm...> > wrote: Op zo 2 nov 2025 om 08:35 schreef apnmbx-public: > > TIP 732: Changes to the Tcl script library search path is ready for comments. .... > I’m particularly interested in feedback from Unix and macOS folks that build distributions if this impacts them in any way. Well, I like this TIP, but there is a test failure on MacOS: <https://github.com/tcltk/tcl/actions/runs/18965835171/job/54162420957> ==== unixInit-3.2 TclpSetInitialEncodings FAILED ==== Contents of test case: set env(LANG) japanese set env(LC_ALL) japanese set f [open "|[list [interpreter]]" w+] chan configure $f -buffering none puts $f {puts [encoding system]; exit} set enc [gets $f] close $f set enc ---- Test generated error; Return code was: 1 ---- Return code should have been one of: 0 2 ---- errorInfo: application-specific initialization failed: Cannot find a usable init.tcl in the following directories: /Users/runner/work/tcl/tcl/lib/tcl9.1 This probably means that Tcl wasn't installed properly. while executing "close $f" ("uplevel" body line 8) invoked from within "uplevel 1 $script" ---- errorCode: NONE ==== unixInit-3.2 FAILED Hope this helps, Jan Nijtmans _______________________________________________ Tcl-Core mailing list Tcl...@li... <mailto:Tcl...@li...> https://lists.sourceforge.net/lists/listinfo/tcl-core |
|
From: <apn...@ya...> - 2025-11-03 16:44:24
|
Harald, Thanks for the summary as always. I wanted to clarify, for the benefit of those not present, my stance with respect to (10) TIP 734 nested mutex as it is still a somewhat controversial issue. I think it may not have been entirely clear from the summary that the comments >Speed is ok, as no additional lock. >Counter is already locked. >All problems are solved now. >No use case in the core. as well as need for consistency were from Jan, not me. I am still not convinced, for lack of data, whether there is a performance loss or not from implementing our own wrappers that implement recursive mutexes. My comment was that since the original code (as I understood the conversation) was derived from NaviServer, it might be educational to run any benchmarks that Gustaf may have with both the current Tcl implementation (recursive wrappers) versus native (non-recursive) mutexes to see if there is an observed difference. Aside from the performance issue, I am philosophically disinclined to implement our own synchronization primitives without a concrete use case or need (which we do not have within the Tcl core or any extensions I know of). I would therefore have been favourably disposed towards 734 except that it reverts a currently released "feature". However, given that recursive mutexes were not available in 8.6 (afaik) and did not work correctly even in 9.0.2, I doubt anyone is actually using that capability and reversion might be acceptable. /Ashok -----Original Message----- From: Harald Oehlmann <har...@el...> Sent: Monday, November 3, 2025 6:36 PM To: Tcl Core List <tcl...@li...> Subject: [TCLCORE] Report of biweekly telco on 3rd of November at 12:00 UTC Dear Tcl/Tk team, here is the report of the Tcl/Tk biweekly telco: 3rd of November at 12:00 UTC At: https://meet.jit.si/TclMonthlyMeetup Top 1) Release calender (TIP 713) - 9.0.3: October (this week) - 9.1a1: November (4 weeks left) Don still in non working block. Wait for new SQLite, for TDBC. A lot of bug fixes for Tk in the pipline. New Tk focused TCT members would be great and are available. Interrim release manager Jan will take care and make rc's. We will wait for SQLite + Tk tickets. Top 2) TIP 672: $(1+1) Great feature. Agreement on the option selection. Will probably not be mature in 1 month. Still a lot of implementation issues. $((1+1)) is fully backward compatible what is great. Top 3) TIP 561: Console command for Linux/Unix Big support, low problem scope. Question is stdin: system and console window both go to the same interpreter stdin. stdout only goes to the console. Linux testing required! Loading by source should be fixed. Top 4) TIP 733: accessability (test status) Great plan. Legal requirements. Top 5) TIP 732: TCL library path (discussion) Great support and to include to 9.1a0 Confused about official MacOS and Linux setup. Also ARM/Intel differences. TOP 6) TIP 615: string is index Implementation not ready jet. Feedback welcome! Tk accepts the empty string as an index to make bindings easier. The "-strict" makes the difference, if enpty string is accepted. Tip text is ready. Aim is 6.1a0 TOP 7) TIP 735: lfilter: "dict filter" for lists, but expr instead eval Great tool! High overlap to lmap. Handling of additional variable proposed. Would be great as an ensemble, but "list" is taken. Top 8) TIP 721: Tcl_AttemptGetString Welcome. No news. Some additional functions on the list. Top 9) TIP 715: supported build systems TCL 9.0 already requests C11, or VS2015. C11 is required for 9.1 to build TCL. The public headers are more conservative (C99). bool is a feature of C11. It is now used internally, not in public headers. Here is the first proposal to use bool in a public API: https://core.tcl-lang.org/tcl/timeline?r=tip-711-bis With a new API, this might be ok. But C bool is different to C++ bool. Compatibality issues to investigate. Top 10) TIP 734 nested mutex (go or not) Discussion with Ashok Speed is ok, as no additional lock. Counter is already locked. All problems are solved now. No use case in the core. We keep track of all mutexes, which adds overhead. I don't understand why there is a global table with all mutextes. A caller is responsible to free mutexes. Inconsistency was on Win/Linux. Now, there is consistency. A panic would be better, but needs additional wrapper code. Benchmark from Gustaf would be great, as we loose performance. Top 11) European conference Will be in July 2025 in Vienna. No alternative on the radar. Top 12) AOB None Top 13) Next meeting: 17th of November 12:00 UTC. Ok for every body. Other dates: (sorry, Harald can not attend to any of them, travelling a lot in November) 4th of November German speaking user meeting 19:00 UTC 11th of November: Monthly TCL meetup 19:00UTC Thank you for all, Harald |
|
From: EricT <tw...@gm...> - 2025-11-03 16:34:35
|
Hi Harald: Regarding, TIP 561: Console command for Linux/Unix In my testing, via a source console.tcl, it does in fact allow input both from the console and the terminal. It even works with rlwrap. What I fixed in the most recent version is the opening and closing of the console window. While the console window is open, no prompts go to the terminal, however. But you can type in commands and the output will go to the console window. On closing, stdout, and stderr both revert to the terminal, and a prompt returns in the terminal window. On issuing another console show, it will now re-open, just where it was and further output to stderr (in red) and stdout go to the console again. That was in my latest fix. Prior to that I was deleting the console window on closing it, which was a mistake. Please try the latest code. I also changed the font size shortcuts to also allow for control-keypad + and - and also control = which is a non-shifted + for convenience. The wrapper code in the tip would provide backward compatibility, i.e. no console would open automatically when running wish, since linux/unix users wouldn't expect that. On the first console show command the wrapper will invoke the contents of console.tcl and then remove itself. Eric On Mon, Nov 3, 2025 at 5:06 AM Harald Oehlmann <har...@el...> wrote: > Dear Tcl/Tk team, > > here is the report of the Tcl/Tk biweekly telco: > 3rd of November at 12:00 UTC > At: https://meet.jit.si/TclMonthlyMeetup > > Top 1) Release calender (TIP 713) > - 9.0.3: October (this week) > - 9.1a1: November (4 weeks left) > > Don still in non working block. > Wait for new SQLite, for TDBC. > A lot of bug fixes for Tk in the pipline. > New Tk focused TCT members would be great and are available. > Interrim release manager Jan will take care and make rc's. > We will wait for SQLite + Tk tickets. > > Top 2) TIP 672: $(1+1) > Great feature. Agreement on the option selection. > Will probably not be mature in 1 month. > Still a lot of implementation issues. > $((1+1)) is fully backward compatible what is great. > > Top 3) TIP 561: Console command for Linux/Unix > Big support, low problem scope. > Question is stdin: system and console window both go to the same > interpreter stdin. > stdout only goes to the console. > Linux testing required! > Loading by source should be fixed. > > Top 4) TIP 733: accessability (test status) > Great plan. Legal requirements. > > Top 5) TIP 732: TCL library path (discussion) > Great support and to include to 9.1a0 > Confused about official MacOS and Linux setup. > Also ARM/Intel differences. > > TOP 6) TIP 615: string is index > Implementation not ready jet. > Feedback welcome! > Tk accepts the empty string as an index to make bindings easier. > The "-strict" makes the difference, if enpty string is accepted. > Tip text is ready. > Aim is 6.1a0 > > TOP 7) TIP 735: lfilter: "dict filter" for lists, but expr instead eval > Great tool! > High overlap to lmap. > Handling of additional variable proposed. > Would be great as an ensemble, but "list" is taken. > > Top 8) TIP 721: Tcl_AttemptGetString > Welcome. No news. Some additional functions on the list. > > Top 9) TIP 715: supported build systems > TCL 9.0 already requests C11, or VS2015. > C11 is required for 9.1 to build TCL. > The public headers are more conservative (C99). > bool is a feature of C11. It is now used internally, not in public headers. > Here is the first proposal to use bool in a public API: > https://core.tcl-lang.org/tcl/timeline?r=tip-711-bis > With a new API, this might be ok. > But C bool is different to C++ bool. Compatibality issues to investigate. > > Top 10) TIP 734 nested mutex (go or not) > Discussion with Ashok > > Speed is ok, as no additional lock. > Counter is already locked. > All problems are solved now. > No use case in the core. > > We keep track of all mutexes, which adds overhead. > I don't understand why there is a global table with all mutextes. > A caller is responsible to free mutexes. > > Inconsistency was on Win/Linux. Now, there is consistency. > A panic would be better, but needs additional wrapper code. > > Benchmark from Gustaf would be great, as we loose performance. > > Top 11) European conference > Will be in July 2025 in Vienna. No alternative on the radar. > > Top 12) AOB > None > > Top 13) Next meeting: > 17th of November 12:00 UTC. > Ok for every body. > > Other dates: (sorry, Harald can not attend to any of them, travelling a > lot in November) > 4th of November German speaking user meeting 19:00 UTC > 11th of November: Monthly TCL meetup 19:00UTC > > Thank you for all, > Harald > _______________________________________________ > Tcl-Core mailing list > Tcl...@li... > https://lists.sourceforge.net/lists/listinfo/tcl-core > |