I have used some TCL, but this construction stumps me.
When $res = "Table does not exist", what will the following return?
[list [list {*}$res]]
I know what [list [list $res]]
would do, but the extra {*}
just baffles me.
Thanks for helping.
When $res = "Table does not exist", what will the following return?
[list [list {*}$res]]
Well, first know that [list {*}…]
is a construct that returns a list of the words in the ellipsis (the contents of the res
variable in your case). It happens that in your case, the net effect is nothing as the input string is actually also a well-formed list. That then becomes a single argument to the outer list
and so we get a single-element list as result, whose element contains a list of the words Table
, does
, not
and exist
in that order, i.e., {Table does not exist}
.
The list of expanded word form is useful for doing concatenation of lists; the concat
command does something similar (but not identical; there are some historical weirdnesses involved in the concat
command). Thus, you'd concatenate two lists like this:
set concatenation [list {*}$list1 {*}$list2]
Also note that expansion (introduced in Tcl 8.5) is true syntax, which is a very unusual thing in Tcl. The {*}
changes the nature of the following substitution so that it yields multiple words instead of just one. While it is possible to do without it, it's actually remarkably difficult to get right. For example, without it the above would be:
set concatenation [eval [linsert $list1 0 list] [lrange $list2 0 end]]
The introduction of expansion has greatly reduced the number of calls to eval
required in most Tcl code (a benefit since it was hard to write properly; a lot of programmers were caught out by the difficulty). This has proved particularly beneficial in practice with the exec
command; it makes working with glob
and auto_execok
much easier:
exec {*}[auto_execok $someCmd] $arg1 {*}[glob *.foo]
# Instead of:
#eval [linsert [auto_execok $someCmd] 0 exec] [linsert [glob *.foo] 0 $arg1]
# Or this _wrong_ version:
#eval exec [auto_execok $someCmd] $arg1 [glob *.foo]
Ugh. That last one was a bit brain-bending to write out in non-expansion form even though I know what I'm doing. (The wrong version is wrong because it falls apart if $arg1
contains Tcl meta-characters…)
It's documented on the Tcl syntax manual page. It's dicussed on the Tcl wiki. It was introduced into the language in TIP 293 (its predecessor was TIP 157 where you can learn how it works).
Essentially, {*}$res
will split the string into its whitespace-separated words. So, [list {*}$res]
acts just like [split $res]
(in this case).
The end result is a list with one element, the list of the words in $res.
Yeah I always find that construction troublesome too. It used be called expand and then they cleverly renamed it to {*} (very memorable!). Anyway I've seen it used to expand a list to make the list contents available.
See this example for an idea of how it works:
% set c [list a b]
a b
% set d [list e f]
e f
% set x [list $c {*}$d]
{a b} e f
% set y [lindex $x 2]
f
% set y [lindex $x 1]
e
% set y [lindex $x 0]
a b
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With