Home > Enterprise >  How to pass multiple dict name to a proc
How to pass multiple dict name to a proc

Time:10-13

Let's say I don't know the name of the dict I have to pass, but I have list for it, so the setup looks like :

set mylist "dict_a dict_b"
dict set dict_a a 1
dict set dict_a b 2
dict set dict_b c 3
dict set dict_b d 4

But now I want to pass all my dict to a procedure (I still don't know the name of the dict, I know only the list of name). I would do something like :

proc test_dict {mylist} {
    foreach element $mylist {
        upvar 1 [subst $element] $element
    }
    foreach dict_ $mylist {
        puts " test of existence : [dict exists $dict_ a]"
    }
}

The answer of tcl is :

test of existence : 0
test of existence : 0

When called with :

test_dict $mylist

I should get 1 and 0 but not this. What is wrong in my proc ?

CodePudding user response:

The problem is that dict exists <dict> <key_name> needs a literal dict or a dictionary value. You are giving the dictionary variable name (not the value).

When you have a variable whose value is the name of another variable, but you need to get the value of that another variable, now there's two levels of interpolation. An easy way to do multiple levels of interpolation is using the set <varname> command (with no second arg).

set first_var 5
set second_var "first_var"
set third_var "second_var"

tcl8.6.8> puts $third_var
second_var
tcl8.6.8> puts $$third_var
$second_var
tcl8.6.8> puts [set $third_var]
first_var
tcl8.6.8> puts [set [set $third_var]]
5

You can fix your proc like this:

proc test_dict {mylist} {
    foreach element $mylist {
        upvar 1 [subst $element] $element
    }
    foreach dict_ $mylist {
        puts " test of existence : [dict exists [set $dict_] a]"
    }
}

CodePudding user response:

The real problem is that you are making local variables with the same name as the arguments. That's a tremendously bad plan as it means that the procedure can't safely use any variable name at all. It's also usually a bad idea to use subst in situations like this, particularly as it is evaluating in the context of the procedure.

Instead, you should use a single loop and reuse the upvar-bound variable:

proc test_dict {mylist} {
    foreach element $mylist {
        upvar 1 $element theDict
        puts " test of existence : [dict exists $theDict a]"
    }
}
  • Related