Search code examples
variablesscopetclprocedure

Tcl variable inside procedure scope issue


I need help with variable scope in tcl

%cat b.tcl

set x 1
set y 2
set z 3

%cat a.tcl

proc test {} {
  source b.tcl
}
test
puts "x : $x, y: $y, z: $z\n"

When I execute this I get can't read "x": no such variable


Solution

  • The source command is almost exactly just the same as this procedure:

    proc source {filename} {
        # Read in the contents of the file
        set f [open $filename]
        set script [read $f]
        close $f
    
        # Evaluate the script in the caller's scope
        uplevel 1 $script
    }
    

    (There are nuances with argument parsing, how the channel is configured, and how things are set up for things like info script and info frame, which make the real thing more complicated. They don't change the overall impression from the above. The real code is implemented in C.)

    In particular, the script is run in the stack frame of the caller, and not in the stack frame of source itself or the global scope. If you want to source in some other scope, you need to use uplevel with the call to source:

    proc test {} {
        # Run the script globally
        uplevel "#0" [list source b.tcl]
    }
    

    In the case where the filename is free of Tcl metacharacters (commonly true of your own code), you can be sloppy:

    proc test {} {
        # Run the script in the caller's scope
        uplevel 1 source b.tcl
    }