Is it possible to assign to a $b ´s value and to b $a ´s value without using a third variable? Is there a function to do so?
Why not just:
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.
My suggestion will swap a-b and vice versa:
foreach {a b} [list $b $a] {}
Although proc let has many other features of course.
proc let { args } { if { [llength $args ] == 2 } { if [string equal [ lindex $args 1 ] "++" ] { set result [ uplevel incr [ lindex $args 0 ] ] } elseif [string equal [ lindex $args 1 ] "--" ] { set result [ uplevel incr [ lindex $args 0 ] -1 ] } else { set result [ uplevel 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 $rest] } else { set result $rest ;# this should always work... } if { "$optional" == "@" } { set max [ llength $result ] foreach var $vars res $result { uplevel 1 [ list set $var $res ] } } else { foreach var $vars { set result [ uplevel [list set $var $result] ] } } } @ { if { "$optional" == ":" } { set rest [uplevel $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 ]] } } + - - - * - / - & - | { foreach var $vars { set result [ uplevel set $var \[ expr \$$var $op ( $rest ) \] ] } } = - default { if { [ catch { set result [ uplevel expr $rest ] } ] } { set result $rest ;# this should always work... } foreach var $vars { set result [ uplevel [list set $var $result] ] } } } } return $result }
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.
RFox See Larry McVoy's L language? extension? to Tcl from Tcl 2006:
http://www.tcl.tk/community/tcl2006/papers/Larry_McVoy/l.pdf
aspect 2015: For interactive use I like to have the following two definitions active (from .tclshrc):
# let <varName> <cmd> <arg>.... 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 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.