'''`[http://www.tcl.tk/man/tcl/TclCmd/Tcl.htm%|%{*}]`''' makes each item in a [list] an individual argument of the current command. `{*}` was new in Tcl [Changes in Tcl/Tk 8.5%|%8.5], and resulted in the [Endekalogue] becoming the [Dodekalogue]. ** See Also ** [{expand}]: the original syntax for this feature, before `{*}` was settled upon. [Expansion with {*} in Tcl 8.4]: [BraceStarBrace]: How should we call this thing? ** Response ** [RLH]: This is much better IMHO. [jcw]: '''HURRAY!''''' [SYStems]: I vote yes. I don't think though that its necessary to deprecate `[{expand}]`, but I agree on deprecating `{}` it does look like syntax error rather than a feature. [RLH]: I think `[{expand}]` should be removed completely. It is not in the language "official" yet and so it should be yanked to make sure no abuse occurs. [JMN]: Well.. `{*}` looks to me like a nipple.. which is clearly better than a wart. ** Documentation ** [http://www.tcl.tk/man/tcl/TclCmd/Tcl.htm%|%official reference]: [TIP] [http://tip.tcl.tk/293%|%293]: ** Description ** '''`{*}`''' '''promotes''' the items in a [list] to individual arguments of the current command. For example, ====== set {*}[list greeting hello] ====== is equivalent to ====== set greeting hello ====== Prior to the introduction of `{*}`, `[eval]` was used for the same purpose, but was difficult to use correctly. In older versions of Tcl, one would write: ====== #warning: no longer recommended eval destroy [winfo children .] eval button .b $stdargs -text \$mytext -bd $border eval exec \$prog $opts1 [getMoreopts] \$file1 \$file2 ====== When used for this purpose, `[eval]` had the nasty habit of breaking apart values that were intended to be single values. When used correctly, it was verbose and inconvenient: ====== #warning: no longer recommended eval exec \$prog [lrange $opts1 0 end] [lrange [getMoreopts] 0 end] \$file1 \$file2 ====== Or: ====== #warning: no longer recommended eval [list exec $prog] [lrange $opts1 0 end] [lrange [getMoreopts] 0 end] [list $file1 $file2] ====== With the new syntax the examples become: ====== destroy {*}[winfo children .] button .b {*}$stdargs -text $mytext -bd $border exec $prog {*}$opts1 {*}[getMoreopts] $file1 $file2 ====== [RS]: One might say {*} is the inverse function of `[list]`: ====== {*}[list a b c] <==> a b c ====== ---- [RS]: In [re_syntax], `*` stands for "zero or more", which is exactly the unique cardinality of an `{*}`ed list... [DKF]: Similarly in `[string match]` syntax. ** Shell Equivalents ** The [bash] equivalent of `{*}` is ======none ${varname[@]:+"${varname[@]}"} ====== ** More Examples ** ======none % set args [list range foobar 2 4] range foobar 2 4 % string $args unknown or ambiguous subcommand "range foobar 2 4" % string {*}$args oba ====== The first time, `[string]` gets the entire value of `$args` as one argument, and fails. The second time, `$args` is expanded, and `[string]`, receiving four separate arguments, works correctly. ---- ======none % proc p args {puts "Number of arguments: [llength $args]"} % p {a b c} Number of arguments: 1 % p {*}{a b c} Number of arguments: 3 ====== ** `{*}` in Multiple Dimensions ** [HaO]: To flatten a matrix, one could use `{*}[[concat {*}...]`. Example to find the max of a matrix: ======none % set m {{1 2} {3 4}} % tcl::mathfunc::max {*}[concat {*}$m] 4 ====== The expression, `{*}[[concat {*}$m]` results in `1 2 3 4`. ** Misc ** CN slightly regrets that `[{expand}]` is now gone - I was looking forward to possible future enhancements along the same line, like for example ====== lappend mylist {sort|toupper|regmatch [0-9]+}$somelist ====== to specify a chain of filters for the expansion. But I suppose that people for whom `[{expand}]` is a wart will classify this a as a tumor... ;-) [DKF]: It's also trivially replacable using `{*}[[...]]` and some commands to preprocess the list. ---- [SYStems] or you can just ====== lappend mylist {*}[lsort [string toupper [regmatch {[0-9]+} $somelist]]] ====== The moral is that `[{*}]` is not a shorthand for other commands, but a new feature, although for this particular example you could have just used ====== set mylist [concat $mylist [lsort [string toupper [regmatch {[0-9]+} $somelist]]] ] ====== [AMG]: Often I need to construct a new list by combining a mixture of lists and elements. This is done very well by combining `[list]` with the `[{*}]` operator. (Is it right to call it an operator?) ====== set l1 {a b c} set e1 d set l2 {e f g} set e2 {h i} set result [list {*}$l1 $e1 {*}$l2 $e2] ====== This sets `$result` to `{a b c d e f g {h i}}`. Equivalent non-`[{*}]` code: ====== set result $l1 lappend result $e1 set result [concat $result $l2] lappend result $e2 ====== [kpv]: Here's a better way of doing with `[concat]` (it's a question of do you special handle the list pieces or element pieces). ====== set result [concat $l1 [list $e1] $l2 [list $e2]] ====== [AMG]: Thanks. This clearly shows the two methods are duals of each other. Side-by-side: ====== set result [list {*}$l1 $e1 {*}$l2 $e2 ] set result [concat $l1 [list $e1] $l2 [list $e2]] ====== In the first method, `[{*}]` is used to mark which elements are to be expanded, and the default is to not expand. In the second method, `[[[list]]` is used to mark which elements are ''not'' to be expanded, and the default is to expand. The latter approach is similar to the behavior of [Unix shells] and has led to a lot of unsafe code when the programmer isn't careful about quoting--- apparently this default is surprising to many people. However, it does work; just be cautious! [kpv]: I think both ways have an equal need for the programmer to be ''cautious'' -- forgetting the `[{*}]` is just as bad as forgetting `[list]`. To me, with years of pre-8.5 programming experience, especially in using `[eval]`, the `[concat]` method feels more natural. I'm sure that will change as I do more 8.5+ programming. ---- [AMG]: When I have a long command but don't feel like using `\` at the end of every line, I sometimes do the following: ====== set data [dict create {*}{ key1 val1 key2 val2 key3 val3 key4 val4 key5 val5 key6 val6 }] ====== Of course, in this case I could have just left out the `[dict create]` and instead relied on the internal representation being generated the first time I tried accessing `$data` as a `[dict]`. But the above is slightly faster and clearer... well, except for the `[{*}]` nonsense, of course. :^) Given a bit of time, I'm sure I could come up with a more realistic example, but I actually find myself doing the above in real code (if anything I write can be said to be "real"). This usage of `[{*}]` provides escaping without turning the arguments into a single argument. Dollar signs and square brackets become ordinary characters, sequences of unquoted whitespace and newlines are delimiters, and the resulting list elements (all of which are pure strings) are placed one-after-the-other into the command's objv list without any extra interpretation. Backslashes, paired braces, and paired double quotes still function as quoting/grouping characters. ("Grouping" means to disable the special meaning of characters that would otherwise be treated as delimiters.) <> Dodekalogue | Syntax | Tcl Syntax