Author: Florent Merlet <[email protected]>
State: Draft
Type: Project
Vote: Pending
Created: 29-Oct-2026
Tcl-Version: 9.2
Keywords: expr, script, proc
Post-History:
Abstract
A script that begins with ( and ends with ) is an expression script:
the whole script is one expression, and its value is the result of the
script.
proc hypot {a b} {( sqrt($a**2 + $b**2) )}
lmap x $list {( $x * 2 )}
It is the second part of TIP 759 (expression syntax in Tcl). It depends
on the expression substitution TIP for one internal piece (the
TCL_TOKEN_SUB_EXPR token in words), not for its syntax.
Rationale
Many scripts are one computation: a procedure body, the body of lmap,
a callback. Today they need expr {...} (or return [expr {...}]). The
expression script removes that noise where it is most frequent, without a
new command: the form comes from the parser, so it works wherever a script
is evaluated, whatever the quoting of the script:
proc sq {x} {($x*$x)} ;# braced
lmap v $L "(\$v+1)" ;# quoted
lmap v $L ($n*2) ;# bare word, substituted before the call
eval {($a + 1)}
Specification
Rule [1] of Tcl(n). A script that begins with an open parenthesis and ends with a close parenthesis (a newline may follow it, as typed in a console) is one expression, parentheses included, evaluated as by
expr. Semicolons and newlines inside it are not command separators. The value of the expression is the result of the script. The value need not be a number:proc greet {} {("Hi there")}returnsHi there, asexpr {("Hi there")}does. In Tcl(n), rule [1] then says that a script is a command script or an expression script, and that commands taking a script, such asprocorforeach, accept both kinds.Only the whole script is tested. A command of a longer script that begins with an open parenthesis is an ordinary command, even when it is the last one and the script ends with a close parenthesis:
eval {set b 5 ($b+1)} ;# invalid command name "(5+1)"The first parenthesis may be closed early:
(1)+(2)is the expression(1)+(2).C API.
Tcl_ParseCommandis unchanged. The evaluator (Tcl_EvalEx) and the bytecode compiler test the whole script before parsing its first command; for an expression script, they take one command of one word, made of oneTCL_TOKEN_SUB_EXPRtoken whose text is the whole script, and the value of that word is the result (it is not a command name). The bytecode compiler compiles it as an expression:proc sq {x} {($x*$x)}compiles toloadScalar; loadScalar; mult; done.Errors are reported as for a command:
invoked from within "(1/0)".
Compatibility
A script that is exactly a call of a command whose name begins with (
and whose last argument ends with ) changes meaning, e.g. (cmd) (x).
(cmd) (x) ; or (cmd) (x) keep the old meaning.
White space
{( and )} are each read as one symbol: a script with white space
before the ( or after the ) is not an expression script. A procedure
body written on several lines keeps the parentheses against the braces:
proc f {x} {(
$x * 2
)}
whereas
proc f {x} {
( $x * 2 )
}
is a call of the command (. This choice is open to discussion.
Alternative considered: expression commands
Instead of a whole script, any command that begins with ( could be an
expression, up to the first ) that leaves the parentheses balanced and is followed by
the end of the command (newline, ;, end of the script, ]):
set x 1
(y = $x * 3)
puts $y
The implementation would be close to this one: only the detection
changes (in Tcl_ParseCommand, at the start of each command), the
compilation and Tcl_EvalEx are the same. It is not
proposed, for fear of incompatibilities: every command whose name begins
with ( would change meaning, anywhere in a script, and white space
before the ( would be allowed, whereas this TIP reads {( and )} as
one symbol. The command [(...)] alone of TIP 759 covers the need to
evaluate an expression for its side effects.
Implementation
Patch 0002-TIP-759-2-7-expression-scripts.patch:
tclParse.c:TclParseExprScriptrecognizes the script; it is called byTclCompileScriptandTclEvalExon the whole script, before the first command.TclSubstTokensevaluates aTCL_TOKEN_SUB_EXPRtoken that does not start with[as a whole.tclCompile.c:TclCompileSubExprcompiles a token that does not start with[as a whole.CompileCommandTokensandTclEvalExalready treat a command of oneTCL_TOKEN_SUB_EXPRword as an expression (TclIsExprCommand, TIP 759).- Tests:
tests/exprScript.test. Documentation:Tcl.n,expr.n.
Copyright
This document has been placed in the public domain.
