Search code examples
scopetclupvar

Tcl/Tk: scope of variables for a function within a function


I'm getting lost on scoping variables in Tcl. I've got two procs I've written and stored in a file that I want to call in another script I'm writing. In my sourced file (which I'll call bar.tcl), I'm using upvar to define a bunch of variables at the beginning of my file that I plan to call within the procs I've defined within bar.tcl, which I'll call bar1 and bar2

I want to call the functions within bar.tcl from my code within foo.tcl. My functions work fine if I'm just interacting with bar.tcl in tclsh, but as soon as I call bar1 or bar2 from within a function in foo.tcl, I get an error can't read "alpha": no such variable

It seems I'm using upvar incorrectlys. Is this even the right tool for the job? What can I do so that I can achieve the following?

  1. define a bunch of variables at the beginning of bar.tcl that I want to use in both procs bar1 and bar2, and
  2. call bar1 and bar2 from within procs defined in foo.tcl

Here's my code in foo.tcl:

# foo.tcl
source bar.tcl

proc foo {fooValues} {
    foreach fooValue $fooValues {
        set myNewValue [bar1 $fooValue]
        return $myNewValue
    }
}

set myOldValues {5 10 15 20 25}
foo myOldValues

And here's my code in bar.tcl:

set a apples
set b bananas
set c cherries
set d dates

proc bar1 {bar} {
    upvar a alpha
    upvar b bravo
    upvar c charlie
    upvar d delta

    set myReturnValue "$bar $alpha $bravo $charlie $delta"
    return $myReturnValue
}

proc bar2 {bar} {
    upvar a alpha
    upvar b bravo
    upvar c charlie
    upvar d delta

    set myReturnValue "$alpha $bravo $charlie $delta $bar"
    return $myReturnValue
}

Solution

  • When bar1, bar2, ... are called from within foo, their upvar calls will try to link with any proc-local variables of the executed foo proc. This is because upvar without level defaults to upvar 1 which denotes the proc's caller (i.e., foo). Your targeted variables in bar.tcl, however, reside in the global namespace and not within foo. Hence, there are no variables linked by alpha, bravo.

    Rewrite your upvar occurrences as upvar #0 ..., with #0 indicating the global, top-level namespace, e.g.:

    upvar "#0" a alpha
    

    This is equivalent to using global a modulo a variable alias (alpha).