TIP 676: Introduce "expr -nosubst" and alias this to "="

Login
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:

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:

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

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.