tcltclsh

Why curly braces allow variable substitution?


Tcl manuals say that curly braces do not allow variable substitution. However this works only with some commands but not with others.

What is the difference and how to identify the cases where the substitution will occur and the cases where it won't occur?

% set x 3
3
% puts {$x}
$x
% expr {$x}
3

Solution

  • Some commands are explicitly described as treating an argument or arguments as a script or an expression; when evaluation of the script or expression happens (which might be immediately, or might be later, depending on the command) the substitutions described inside that string that is a script or expression are performed. (The subst command is a special case that can only apply a selected subset of substitutions.)

    How do you know which is which? It depends on the command. Literally. Go and read the documentation. For example, in the documentation for catch we see:

    SYNOPSIS

    catch script ?resultVarName? ?optionsVarName?

    DESCRIPTION

    The catch command may be used to prevent errors from aborting command interpretation. The catch command calls the Tcl interpreter recursively to execute script, and always returns without raising an error, regardless of any errors that might occur while executing script. […]

    In this case, we see that the first argument is always evaluated (immediately) as a Tcl script by calling the Tcl interpreter (or rather it's actually bytecode compiled in most cases, but that's an implementation detail).

    Similarly, in the documentation for proc we see:

    SYNOPSIS

    proc name args body

    DESCRIPTION

    The proc command creates a new Tcl procedure named name, replacing any existing command or procedure there may have been by that name. Whenever the new command is invoked, the contents of body will be executed by the Tcl interpreter. […]

    In this case, it's the body that is going to be evaluated as a script (“by the Tcl interpreter” is a form of language that means that) but later, when the procedure is called. (catch said nothing about that; by implication, it acts immediately.)

    A third case is the documentation for while:

    SYNOPSIS

    while test body

    DESCRIPTION

    The while command evaluates test as an expression (in the same way that expr evaluates its argument). The value of the expression must a proper boolean value; if it is a true value then body is executed by passing it to the Tcl interpreter. […]

    From this, we can see that the test argument is an expression (which uses expression rules) and body is a script.


    If you want to create a substitution-free single-command script where you can use arbitrary values for everything (this perfect for setting up a callback) use the list command as that is defined to produce lists in canonical form, which happens (by design) to be exactly the form that single commands without substitution-surprises can take:

    set xyz "123 456"
    set callback [list puts $xyz]
    set xyz {[crash bang wallop]}
    puts "READY..."
    eval $callback