'''Let's assign with let''' presents techniques to assign data to multiple variables. For example, one might transpose the value of two variables. ** See Also ** [http://www.tcl.tk/community/tcl2006/papers/Larry_McVoy/l.pdf%|%L], by [Larry McVoy]: ** Let ** ====== proc let args { if {[llength $args] == 2} { if {[lindex $args 1] eq {++}} { set result [uplevel 1 [list ::incr [lindex $args 0 ]]] } elseif {[lindex $args 1] eq {--}} { set result [uplevel 1 [list ::incr [lindex $args 0] -1]] } else { set result [uplevel 1 [list ::set {*}$args]] } } else { regexp {([^=:+\-*/&|@]*)([:+\-*/&|@]?)([@]*)=(.*)} $args -> vars op optional rest if {![info exists op]} { return -code error -errorcode 1 "no valid assignment operator in $args" } switch $op { : { if {[llength [info commands [lindex $rest 0]]]} { set result [uplevel 1 $rest] } else { # this should always work... set result $rest } if { $optional eq {@}} { set max [llength $result] foreach var $vars res $result { uplevel 1 [list ::set $var $res] } } else { foreach var $vars { set result [uplevel 1 [list ::set $var $result]] } } } @ { if {$optional eq {:}} { set rest [uplevel 1 [list {*}$rest]] } set max [llength $rest] if {$max == 1} { eval set rest $rest set max [llength $rest] } foreach var $vars res $rest { set result [uplevel 1 [list ::set $var $res]] } } + - - - * - / - & - | { set script {} foreach var $vars { append script " ::set [list $var] \[ ::expr {\[::set [list $var]] $op ($rest)}] " } set result [uplevel 1 $script] } = - default { if {[catch {set result [uplevel 1 ::expr \{$rest\}]}]} { # this should always work... set result $rest } foreach var $vars { set result [uplevel 1 [list ::set $var $result]] } } } } return $result } ====== Example: Transposing two variables: ====== let a b @= $b $a ====== Which, by the way, also allows: ====== let a b c = 1 ;#this sets a b and c to 1 let a b c = 1 + 4 ;#"=" uses expr to process the value to assign let a b c += 1 ;#computed assignments are allowed, +-*/&| supported let a b c := info commands ;#uses eval to process right side let a b c @= 1 2 3 ;#instead of assigning the list {1 2 3} to a b and c, ;#it instead assigns the elements in order, resulting ;#in a getting the value 1, b getting 2 and so on. let a b c @:= info commands ;#uses eval to get result and uses @= for assignment let a ++ ;#incr and let a -- ;#decr are supported. ====== ---- [RS] The code fragment (appears twice above) ====== set i 0 foreach var $vars { uplevel set $var [ lindex $result $i ] incr i } ====== seems like it can be replaced by ====== foreach var $vars res $result { uplevel 1 [list set $var $res] } ====== - if `[foreach]` can do a job once, it might as well do it twice ;-) A variable saved, and possibly safer with the `[list]` wrapper... [Larry Smith]: I'd clean forgotten that feature. Yes, it's much more elegant that way. The above code has been corrected. ** `[foreach]` ** My suggestion will swap a-b and vice versa: ====== foreach {a b} [list $b $a] {} ====== Although `let` has many other features of course. ** Avoiding Brackets ** [aspect] 2015: For interactive use I like to have the following two definitions active (from [.tclshrc]): ====== # let .... proc let {name args} { tailcall ::set $name [uplevel 1 $args] } interp alias {} = {} expr ====== The mostly saves me having to contort my fingers to write `[[expr {` and `}]]`. The specific combination using `=` as a pun for expr I find more Tclish than `=` as an always-present keyword argument. ====== let pi = 4*atan(1) ====== Of course the resulting code is suboptimal and dangerous ([Brace your expr-essions%|%Brace your expressions]!), but it is a lot more fun to write. The only problem is that before publication I need to clean up, but that's a few editor macros away. You will find some of the toys I paste to the wiki use this combination, where I feel readability trumps robustness. ** Page Authors ** [pyk]: <> Uncategorized