TIP 680: Enhance definition of a "number" in Tcl

Login
EuroTcl/OpenACS 11 - 12 JULY 2024, VIENNA
Author:         Brian Griffin
State:          Withdrawn
Type:           Project
Vote:           Pending
Tcl-Version:    9.1

Abstract

Enhance the core GetInt, GetDouble, GetBoolean implementations to accept valid [expr] expressions, computing and returning the resulting value on each invocation.

Rationale

In cases where arguments to commands are expected to be numbers, integer or real, it is not uncommon to have some calculations required to predetermine the value needed for the command. This is sometimes written with inline expr command substitutions.

.c create text [expr {$x+1}] [expr {$y+1}] -text a

It would be nice to make complex lines like the above, easier to read:

.c create text {$x+1} {$y+1} -text a

Now the command looks more like other (expression based) programming languages.

Specification

Modify the Tcl_GetInt(), etc., by attempting to parse an expression after failing to parse a valid number. If it fails, then report the normal invalid number error, otherwise, evaluate the expression, confirm that the result is a valid number, and return the number or an error as appropriate.

The code should also check the Tcl_ObjType for an already compiled expression to short circuit the string parsing steps.

Discussion

From TIP 674:

Gustaf Neumann:

This is an interesting idea, somewhat similar to the index expressions, but with the difference that these "number expressions" could be used everywhere (for all arguments, but also in other locations, where Tcl_GetInt*() is not meant to parse an argument). The latter concerns me a little, since it has implications on provided stack frames for resolving variables etc. For me, the exact implications are not clear.

Peter Da Silva:

You could avoid breaking any existing code or unexpectedly opening up a new attack surface by using something like the {*} hack.

.canvas enclosed {$}{$x + 20} {$}{$x - 20} {$}{$y + 20} {$}{$y - 20}

vs

.canvas enclosed [expr {$x + 20}] [expr {$x - 20}] [expr {$y + 20}] [expr {$y - 20}]

Donal Fellows:

Now that's a much more sensible suggestion; no unexpected trouble in scripts because it is currently definitely an error. I guess we'd need to pick an initial indicator syntax (either {=} or {$} would work).

Having canvases do falling back to calling Tcl_Expr() on their coordinate arguments isn't as good; they need to determine (in item creation particularly) whether an argument is numeric in order to decide when to stop parsing values as coordinates and start parsing them as options. It certainly would be possible, but there would be some weird edge cases and the performance would likely be terrible.

Colin Macleod:

This could work (I would prefer {=} to {$} but that's a detail). However this would require updating the Dodecalogue, so again it's much deeper change than what I proposed in tip 676.

Also I think Peter's warning about "opening up a new attack surface" should be taken seriously. There may be old code which accepts user input and then uses it in a numeric context without validation. In the past bad input would just have caused an error. If a new version of Tcl makes it possible to enter "1/0" or "[puts $::password] ? 2 : 3" and get this run, it will not be popular.

Brian Griffin:

Variable scoping and expressions with side effects (e.g. [expr {$a +[incr y]}] ) are a serious issue. If a command processes arguments out of order, then side-effects will have unexpected behavior.

I do not think the attack surface is any different in any of these solutions. [expr] is another form of [eval], no matter what other new short-hand syntax is invented. Any code that effectively does an [eval] on unwashed data is vulnerable.

I think the side effects issue alone is enough to disqualify TIP #680.

Copyright

This document has been placed in the public domain.