'''`[Dodekalogue%|%{*}]`''' 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 ** `[eval]`: contains a copy of a post to [comp.lang.tcl] by [Jeff Hobbs] explaining the multiple layers of the problem with `[eval]`, and how something like `{*}` solves the problem. [{expand}]: the original syntax for this feature, before `{*}` was settled upon. [Expansion with {*} in Tcl 8.4]: [BraceStarBrace]: How should we call this thing? [Unix Shells]: compares `{*}` to Unix shell syntax ** Response ** [RLH]: This is much better IMHO. [jcw]: '''HURRAY!''' ** Documentation ** [http://www.tcl.tk/man/tcl/TclCmd/Tcl.htm%|%official reference]: [TIP] [http://tip.tcl.tk/293%|%157]: describes the rationale for and functionality of `{*}`, but uses the `{expand}` notation. [TIP] [http://tip.tcl.tk/293%|%293]: proposes `{*}` instead of `{expand}` ** 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] et al: a series of literal arguments to a command can be expressed in `{*}` form: ====== set data [dict create {*}{ key1 val1 key2 val2 key3 val3 key4 val4 key5 val5 key6 val6 }] ====== Of course, in this case the `[dict create]` could have been left out, and the internal `[dict]` representation have been generated the first `$data` was used 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, since the the resulting list elements (all of which are literal strings) each become an argument to the command, without any extra interpretation. Since the value following `{*}` is a well-formed list, standard `[list]` formatting can be employed, including backslashes, paired braces, and paired double quotes. <> Dodekalogue | Syntax | Tcl Syntax