Search code examples
settclproc

tcl how to redefine "set" command


I am new comming of tcl. How to use tcl to imitate "set" command?

I try to build like below cold, but below code with error: unknown command name:

proc my_set {varName {value ""}} {
  uplevel 0 [set $varName $value]
}
my_set a "123"
my_set b(a) "good"

puts $a; #expected: 123
puts $b(a); #expected: good

Solution

  • In your my_set proc, the script set $varname $value is called, and then its result is passed as an argument to the uplevel command, which will try to run that result as a script.

    To have it do what you want:

    proc my_set {varname {value ""}} {
        uplevel 1 [list set $varname $value]
    }
    

    or

    proc my_set {varname {value ""}} {
        upvar 1 $varname target
        set target $value
    }
    

    or

    proc my_set {varname {value ""}} {
        tailcall set $varname $value
    }
    

    The first (using uplevel) constructs the command to run in the caller's frame (the 1 argument) as a list, and then uplevel runs that list as a command 1 frame up the stack.

    The second aliases the local variable target in the my_set proc to the variable whose name is in the varname variable, 1 level up the stack. So setting the target variable within the my_set proc also sets the variable called $varname in the caller's frame.

    The third (using tailcall) replaces the callframe of the my_set with the command set, which is then executing as if it was called from the parent frame.

    Of the three, I would probably pick the second (using upvar) because there is less potential for nasty surprises waiting in your future (uplevel is essentially eval - incautious use can open remote code execution vulnerabilities), and, unless you like obscure constructions for their own sake, the tailcall implementation is probably just too weird.