Version 0 of Block-local variables

Updated 2001-03-01 09:59:41

Richard Suchenwirth - After a weekend without fun project, here's a little midnight study on local variables - inspired by reading on Scheme's let construct. I preferred the name with which sounded even more commonsense to me.

Tcl variables are either global, or local to a procedure. You can shorten a variable's lifetime with unset. In LISP/Scheme as well as in C (as unequal they otherwise are), you can have variables local to a block of code - in LISP enclosed by let, in C by just bracing a block. And you can have that in Tcl too, as shall presently be demonstrated. The with command takes a non-empty list of variable names (with optional initial values, like a proc arglist) and a body which must refer to those variables, executes the body in caller's scope, and unsets the "local" variables afterwards.

 proc with {locals body} {
    set cleanup [list unset]
    foreach i $locals {
        set name [lindex $i 0]
        if [uplevel info exists $name] {
            return -code error "local variable $name shadows outer var."
        }
        lappend cleanup $name
        if [llength $i]==2 {
            uplevel 1 set $i ;# uplevel works like concat, so no eval
        }
    }
    set res [uplevel 1 $body]
    uplevel 1 $cleanup
    set res
 }

# usage example and test code:

    set x 17
    with {xa xb {xc 5}} {
        set xa [expr $xc*$xc]
        set xb [incr xa $x]
        puts xb=$xb
    }
    puts "now we have [info vars x*]" ;# should not show xa, xb, xc

Discussion: The handling of local variables with same name as one in outer scope is more strict than in C (where it may raise a warning) or Lisp (where it's no problem at all - the local temporarily supersedes the outer, which is later available unchanged). Since body is just upleveled, any other treatment seemed dangerous or overly difficult - but feel free to improve on that... Likewise, specifying a local variable which is not set to a value in body, or not giving any locals at all, raises an error on unsetting. As usual, another error is raised when retrieving a variable's value that has not been set before.

How useful this is, is another question. Good efficient code should be written inside procedures, and variables inside procedures are local anyway unless explicitly globalized.


Local procedures - Arts and crafts of Tcl-Tk programming