|
From: Colin M. <col...@ya...> - 2025-11-11 10:25:15
|
HI All, Sorry, I would not plan to do assignments or multiple calculations in the first version of [=]. I would leave these as possible enhancements for later. I do think there is less need for these features anyway if a single expression can be written concisely. I have put an updated version of my prototype at https://cmacleod.me.uk/tcl/expr_ng2. This incorporates the cache Eric introduced, but then diverges from his version somewhat. I have kept the command name as `=`, I think that's more clear than `:` to introduce a calculation. I have introduced an `extract_numbers` step before tokenisation. The point of this is to enable pre-substituted array elements e.g. $a(b) or command substitutions, e.g. [llength $list], which produce numeric values, to be used efficiently. If these are written as separate arguments (separated by spaces from the rest of the expression) then we check whether that argument already has a numeric internal representation. If so, we assign it to a temporary variable and replace it in the expression with a reference to that temporary variable. This avoids shimmering the value to/from string form. But more importantly it allows us to cache the generated bytecode, because the name of the temporary variable will stay the same although its value may change. Writing the `extract_numbers` step in Tcl is extremely kludgy, it does a regexp match on the output of tcl::unsupported::representation, ignoring the warning at https://wiki.tcl-lang.org/page/representation that this should not be used in program logic. It's also slow, though still faster than invalidating the cache. But I still see this prototype as a precursor to implementation in C, so I'm not too worried. Some timings: Without `extract_numbers`, expression without pre-substitution: (bin) 149 % timerate {set z [= z *0.9999]} 2.246294 µs/# 445176 # 445177 #/sec 999.996 net-ms Without `extract_numbers`, expression with pre-substitution: (bin) 151 % timerate {set z [= $z *0.9999]} 22.4901 µs/# 110649 # 44464.1 #/sec 2488.502 net-ms With `extract_numbers`, expression without pre-substitution: (bin) 153 % timerate {set z [= z *0.9999]} 13.6414 µs/# 73306 # 73306.1 #/sec 999.999 net-ms With `extract_numbers`, expression with pre-substitution: (bin) 154 % timerate {set z [= $z *0.9999]} 15.7187 µs/# 63618 # 63618.6 #/sec 999.990 net-ms So even with the klunky Tcl implementation the `extract_numbers` step still gives a speed-up when there is a pre-substituted numeric value. A C implementation of this logic should be much more efficient. Of course this speed-up is lost if a pre-substitution is not written as a separate argument, e.g. [= [llength $l] +2] will get the speed-up but [= [llength $l]+2] will not, so the documentation should warn about this. Colin. On 10/11/2025 07:20, Zaumseil René via Tcl-Core wrote: > > Hi Eric > > Thank you for your effort to bring this topic forward. > > Imho Colin's syntax is even better as the let version. > > I hope one of your proposals will make it into the core. > > Regards > > rene > > *Von:*EricT <tw...@gm...> > *Gesendet:* Freitag, 7. November 2025 21:35 > *An:* Zaumseil René <RZa...@kk...> > *Cc:* tc...@ro...; tcl...@li... > *Betreff:* Re: [TCLCORE] [Ext] Re: [=] for concise expressions (was > Re: TIP 672 Implementation Complete - Ready for Sponsorship) > > Rene, > > That's the beauty of making bytecode compilation official - we DON'T > have to agree on syntax! With a supported tcl::bytecode API, each of > us can create our own Design-Specific Language for our own needs. No > more "one size fits all" debates that go nowhere. > > That said, I think you might find Colin's approach already fits your > needs quite well. Here's how your examples would look: > > Multiple assignments: > > # Your let syntax > let {x 1+2 y 3*4 z $x+$y} > > # Colin's syntax (bare variables, no $) > : {x = 1+2 > y = 3*4 > z = x+y} > > > For my own taste, I've here aliased = to : since = as the command > seems to clash visually with = for assignment, especially in cases > like a = b = c = d. The semicolon requires braces since it's special > to Tcl, but by mapping newlines to semicolons internally, multiple > statements work naturally in braced blocks as shown above. > > Returning multiple values: > > # With a simple helper function > proc tcl::mathfunc::gather {args} { list {*}$args } > > # Your canvas example > .c create text {*}[= gather(x+1, y+1)] -text a > > # Or inline > = {tx = x+1 ; ty = y+1 ; gather(tx, ty)} > > > Your calculations example: > > set i 0.5 > = {x = sin(i) > y = cos(i) + x > z = x + y} > > > The key differences: bare variables (no $), explicit = for assignment, > semicolon (or newline) to separate multiple expressions, and gather() > for multiple returns. But it's all extensible - add your own functions > to tcl::mathfunc:: and they're automatically available. > > If you prefer different syntax, you can build your let command using > the same bytecode infrastructure. That's the whole point - multiple > DSLs coexisting, each optimized by bytecode caching. > > > Eric > |