tclglobal

How to write a procedure in TCL that will use either a global dictionary or another one


I have a procedure that use a global dictionary. it is a global one because I need the procedure to be able to read inside the dictionary and update it.

I need to be able to use either this global dictionary dict_glob1 or another dictionary dict_glob2 depending on a argument of the procedure.

I could provide as argument the correct dictionary but then I'm afraid I won't be able to update it. In fact I guess I need to be able to provide only the "name" of the global dictionary. but I don't know how to link the "name" of the dictionary with the real dictionary inside the procedure.


Solution

  • The easiest method is to use upvar (plus whatever logic you need to decode the argument) to give the variable you want to access/update a consistent local name within your procedure. That keeps the complexity in the vicinity of setting up the upvar call; everything after that is simple (or at least just as complex as it needs to be).

    Here's a contrived version (d is just a local variable name that's a bit mnemonic for "dictionary"):

    proc doTheThing {{argument "foo"}} {
        if {$argument eq "foo"} {
            upvar "#0" dict_glob1 d
        } else {
            upvar 1 dict_glob2 d
        }
    
        dict set d abc 123
    }
    

    It's more normal for variable names to be always passed as arguments by the caller. They can name global variables if they want. In that case, you'd get:

    proc doTheThing {{varName "::dict_glob1"}} {
        upvar 1 $varName d
        dict set d abc 123
    }
    

    In this case, we're naming a global variable as a default argument, but the caller can override it to be any other name (either namespaced or in their scope) that they prefer it to be.