Version 19 of Let's assign with let

Updated 2011-10-19 11:45:19 by RFox

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