mkostya
mkostya

Reputation: 972

Using TCL eval command with "set"

Here is the code I am testing:

proc check_eval {} {
    set cmd {set return_val {}; set return_val}
    puts "Command to evaluate : $cmd"
    uplevel eval $cmd
}

I encountered the following problem: when I am calling "check_eval", it looks like the statement "set return_val {}" is ignored. I.e., the interpeter looks for existing return_val variable in the calling scope. Example:

tcl>unset return_val
tcl>check_eval
Command to evaluate : set return_val {}; set return_val
can't read "return_val": no such variable
while evaluating check_eval


tcl>set return_val 556
556
tcl>check_eval
Command to evaluate : set return_val {}; set return_val
556
tcl>

On the other hand, if I replace "set return_val {}" in the procedure by, for example, "set return_val 10000", it will show 10000 when running:

tcl>set return_val 556
556
tcl>check_eval
Command to evaluate : set return_val 10000; set return_val
10000
tcl>set return_val
10000

Does anybody can explain me please what is going on here?

Thanks.

Upvotes: 2

Views: 2358

Answers (1)

potrzebie
potrzebie

Reputation: 1798

You're doing two levels of evaluation/interpreting, first with uplevel then with eval, and the brace grouping around the cmd script only protects you from the first one.

You don't need eval, this will suffice:

uplevel $cmd

EDIT: Both eval and uplevel concat:enate all their arguments together into a flat string and evaluate it as a script (with uplevel you can choose another stack frame to run it in). They don't use the first argument as a single command name and the rest of the arguments as arguments to send to that command. If that was the case, you'd get an error message from your eval that the command "set return_val {}; set return_val" couldn't be found. So you're using eval correctly but uplevel wrong.

uplevel runs this script...

eval set return_val {}; set return_val

...which is broken in more ways than one, because you didn't list quote (group) it's arguments.

eval isn't needed in your example, but should you need to call a single command uplevel, without it's arguments getting concatenated, the way to quote static strings when you don't need any substitutions, is with braces:

uplevel {after 1000 {set return_val {}; set return_val}}

...and the way to quote dynamic strings with substituted values in it, is with list:

set cmd {set return_val {}; set return_val}
uplevel [list after 1000 $cmd]

Upvotes: 4

Related Questions