skorada
skorada

Reputation: 461

Variable substitution in a list in Tcl

I am trying to substitute a variable in a list:

% set a 1  
1  
% set b {1 $a}  
1 $a  
%  
% set a 1  
1  
% set b [list 1 $a]  
1 1  

When I use the curly braces {}, to define the list the variable 'a' doesn't get substituted with its value but in case of using list it does.

How do I substitute a variable's value when using a list defined with {}?

Upvotes: 3

Views: 7016

Answers (2)

Donal Fellows
Donal Fellows

Reputation: 137567

How do I substitute a variable's value when using a list defined with {}?

In short, you don't.

What {} really does is define an unsubstituted string. It might be possible to interpret that as a list, but it could be other things as well, such as script. It's part of the fundamental nature of Tcl that it is all of these things.

If you want the variable substituted, you use a different sort of quoting or you run the result through subst (which is defined to work over strings). The “quoting” most commonly used for lists these days is the list command, as that preserves element boundaries correctly.

I suppose it is possible to do things with various string operations to make a command that could post-process the string as you want, but it would be slow and complicated:

proc substList {string} {
    # Add backslashes in front of metacharacters
    set safer [string map {\\ \\\\ [ \\[ ] \\]} $string]
    # Convert variable mentions to our “safe” version
    regsub -all {\$\w+} $safer {[list &]} tmpl
    # Do the substitutions in the caller's context
    tailcall subst $tmpl
}

Giving a quick test:

% set a "1 2 3"
1 2 3
% set b {x $a}
x $a
% substList $b
x {1 2 3}

Appears to work in this simple case, though I wouldn't want to warrant that it's actually right. (After all, it's using string map and regexp and subst; what could possibly go wrong?) Just use list properly, OK?

Upvotes: 1

Peter Lewerin
Peter Lewerin

Reputation: 13252

% set a 1
1
% subst {1 $a}
1 1
% set b [subst {1 $a}]
1 1

But most Tcl:ers actually prefer to use list when creating a list value with substitutions, like in your second try:

% set b [list 1 $a]

One reason for this is that subst won't preserve list structure in the value:

% set a {a b}
a b
% set b [subst {1 $a}]
1 a b
% set b [list 1 $a]
1 {a b}

Another possibility is to use double quotes instead of braces; this also won't preserve list structure.

% set b "1 $a"
1 a b

Documentation: list, set, subst, Summary of Tcl language syntax

Upvotes: 5

Related Questions