Author: Colin Macleod <[email protected]>
State: Draft
Type: Project
Vote: Pending
Tcl-Version: 9.0
Created: 23-Jun-2023
Abstract
This TIP proposes adding an option -nosubst to the expr command, which will disable all substitutions (variable, command, backslash) applied by expr's own code. This will make it possible to use unquoted arguments with expr while avoiding the well-known problems of double substitution.
It also proposes to make a standard predefined alias of = to expr -nosubst which will permit numeric computations to be written within other commands in a more compact and natural form than at present, with no modification to Tcl's parsing rules.
Rationale
Most newcomers to Tcl, and some oldies, find expr awkward. The requirement to brace expressions for safety and performance leads to e.g. a canvas command with computed coordinates looking like:
.canvas addtag enclosed [expr {$x - 20}] [expr {$x + 20}] \
[expr {$y - 20}] [expr {$y + 20}]
The wiki page https://wiki.tcl-lang.org/page/expr+shorthand+for+Tcl9 records many suggestions for a more compact syntax, one of which has also been proposed in TIP 672. This shows that the issue has been a concern for many years. However all of these proposals involve changing the basic Tcl parsing rules (the dodekalogue), which has a major impact in terms of extra complexity and backward compatibility. This TIP aims to allow such inline expressions to be as concise as possible without changing Tcl's parsing rules. The effect will be to allow the canvas command above to be written as:
.canvas addtag enclosed [= $x - 20] [= $x + 20] [= $y - 20] [= $y + 20]
or even:
.canvas addtag enclosed [= $x-20] [= $x+20] [= $y-20] [= $y+20]
Note that the values of variables (x and y in the example above) will have
been substituted into the expression before expr
is invoked, so the
-nosubst
option is used to prevent a second round of substition.
There are some downsides to this method:
It would be difficult to supply non-numeric arguments - strings or lists - since the quoting around them would be stripped off before
expr
saw them.Lazy evaluation of
&&
,||
and?:
would not be possible.
But many uses of expr
are for simple numeric calculations where these
restrictions do not matter, but brevity is desirable. The standard expr
would still be available for use in the other cases.
In the form without spaces (e.g. [= $x-20]
above) we could have a loss of
precision for floating point values because they will be converted to string
form and then back again. There is no such loss for integers though. When
spaces are used around a variable (e.g. [= $x - 20]
above) it may be
possible to avoid converting it to/from string form, this needs investigation.
An alternative which already exists for inline calculations is to use
operations from the mathop
namespace in prefix form. However this is rather
obscure to people who are not Tcl experts, and becomes awkward if several
different operators need to be combined.
TIP 526 proposes restricting expr
to a single argument. This would not make
sense when -nosubst
is used, but could still be done when -nosubst
is not
used.
Specification
The expr
command will take an optional flag -nosubst
. Note that expr
-nosubst ...
will currently produce an error: invalid bareword "nosubst"
so
this change will not break any working scripts. The syntax will become:
- expr ?-nosubst? arg ?arg arg ...?
When the -nosubst
flag is supplied, no substitutions (variable, command,
backslash) will be performed by the expr
command. Any variable or other
substitutions which are desired should be done by the usual Tcl means before
the expr
command is invoked, therefore the arguments to expr
should not
be braced unless a constant is being computed.
The following alias will be predefined:
interp alias {} = {} expr -nosubst
Defining this as an alias will allow any existing code which defines an "="
command to continue working. However new code can use [= <expr>]
as a
compact way to make a calculation.
Options
This functionality could be implemented as a separate command, perhaps
calc
, rather than as an option toexpr
. If so the new command could be defined to provide only the numeric and boolean operations fromexpr
to avoid problems with quoting of strings and lists.There could be a case for making the control of substitutions more fine-grained, as can be done in the
subst
command. For example a program which allowed users to enter arbitrary expressions for evaluation might wish to allow variable substitution but disable command substitution.It could be useful to have an option to control the interpretation of barewords rather than just rejecting them, by supplying code that would be invoked to determine a value for them. E.g. this could return 3.14159 for "pi", etc.
Discussion
Examples
Setting a variable:
set bright [= $red * 0.3 + $green * 0.59 + $blue * 0.11]
set x [= $radius * cos($angle) ]
Use with an image command:
my_img put $shade -to [= $left+$i] $top [= $left+$i+1] $bottom
Implementation
Implementation is yet to be done, however since it is mainly disabling existing functionality, one would hope it should be straightforward.
Discussion
Copyright
This document has been placed in the public domain.